diff options
| author | ruki <[email protected]> | 2026-01-30 00:58:01 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2026-01-30 00:58:01 +0800 |
| commit | 499feec6a33984747dd235b860af7f6b5cc2a1e3 (patch) | |
| tree | dfb74cb21a36f487b9b581f92e913126e9c2e317 | |
| parent | 148404f78b74d376eba5922cb197162a9f05b1a7 (diff) | |
improve binutils.format
| -rw-r--r-- | core/src/xmake/binutils/ar/prefix.h | 2 | ||||
| -rw-r--r-- | core/src/xmake/binutils/ar/readsyms.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/binutils/deplibs.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/binutils/extractlib.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/binutils/format.c | 209 | ||||
| -rw-r--r-- | core/src/xmake/binutils/mslib/readsyms.c | 2 | ||||
| -rw-r--r-- | core/src/xmake/binutils/prefix.h | 135 | ||||
| -rw-r--r-- | core/src/xmake/binutils/readsyms.c | 3 | ||||
| -rw-r--r-- | core/src/xmake/binutils/rpath.c | 4 |
9 files changed, 222 insertions, 139 deletions
diff --git a/core/src/xmake/binutils/ar/prefix.h b/core/src/xmake/binutils/ar/prefix.h index 862a3923b..cf6f58d03 100644 --- a/core/src/xmake/binutils/ar/prefix.h +++ b/core/src/xmake/binutils/ar/prefix.h @@ -35,7 +35,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_int_t xm_binutils_detect_format(tb_stream_ref_t istream); +extern tb_int_t xm_binutils_format_detect(tb_stream_ref_t istream); /* ////////////////////////////////////////////////////////////////////////////////////// * types diff --git a/core/src/xmake/binutils/ar/readsyms.c b/core/src/xmake/binutils/ar/readsyms.c index a41bf2e33..9a4ff97de 100644 --- a/core/src/xmake/binutils/ar/readsyms.c +++ b/core/src/xmake/binutils/ar/readsyms.c @@ -351,7 +351,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_detect_format(istream); + tb_int_t format = xm_binutils_format_detect(istream); if (format != XM_BINUTILS_FORMAT_AR) { // create entry table lua_newtable(lua); diff --git a/core/src/xmake/binutils/deplibs.c b/core/src/xmake/binutils/deplibs.c index 289e656a0..48a7cd200 100644 --- a/core/src/xmake/binutils/deplibs.c +++ b/core/src/xmake/binutils/deplibs.c @@ -73,7 +73,7 @@ tb_int_t xm_binutils_deplibs(lua_State *lua) { } // detect format - tb_int_t format = xm_binutils_detect_format(istream); + 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"); diff --git a/core/src/xmake/binutils/extractlib.c b/core/src/xmake/binutils/extractlib.c index ec588f213..5e6559082 100644 --- a/core/src/xmake/binutils/extractlib.c +++ b/core/src/xmake/binutils/extractlib.c @@ -87,7 +87,7 @@ tb_int_t xm_binutils_extractlib(lua_State *lua) { } // detect format - tb_int_t format = xm_binutils_detect_format(istream); + tb_int_t format = xm_binutils_format_detect(istream); if (format < 0) { error_msg = "cannot detect format"; break; diff --git a/core/src/xmake/binutils/format.c b/core/src/xmake/binutils/format.c new file mode 100644 index 000000000..7adf38aa0 --- /dev/null +++ b/core/src/xmake/binutils/format.c @@ -0,0 +1,209 @@ +/*!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 format.c + * + */ +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "format" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ +static tb_bool_t xm_binutils_format_detect_pe(tb_stream_ref_t istream, tb_byte_t* first8) { + tb_assert_and_check_return_val(istream && first8, tb_false); + if (!((first8[0] == 'M' && first8[1] == 'Z') || (first8[0] == 'Z' && first8[1] == 'M'))) { + return tb_false; + } + + tb_bool_t ok = tb_false; + do { + tb_hong_t size = tb_stream_size(istream); + if (size > 0 && size < XM_BINUTILS_PE_DOS_STUB_MIN_SIZE + 4) { + break; + } + + tb_size_t max_peek = 4096; + if (size > 0) { + max_peek = (tb_size_t)tb_min((tb_hize_t)max_peek, (tb_hize_t)size); + } + + tb_byte_t* p = tb_null; + if (!tb_stream_peek(istream, &p, max_peek)) { + break; + } + + tb_uint32_t e_lfanew = (tb_uint32_t)( (tb_uint32_t)p[XM_BINUTILS_PE_DOS_ELFANEW_OFFSET] + | ((tb_uint32_t)p[XM_BINUTILS_PE_DOS_ELFANEW_OFFSET + 1] << 8) + | ((tb_uint32_t)p[XM_BINUTILS_PE_DOS_ELFANEW_OFFSET + 2] << 16) + | ((tb_uint32_t)p[XM_BINUTILS_PE_DOS_ELFANEW_OFFSET + 3] << 24)); + tb_check_break(e_lfanew >= XM_BINUTILS_PE_DOS_STUB_MIN_SIZE); + tb_check_break((tb_size_t)e_lfanew + 4 <= max_peek); + tb_check_break(size <= 0 || (tb_hize_t)e_lfanew + 4 <= (tb_hize_t)size); + + tb_byte_t const* signature = p + (tb_size_t)e_lfanew; + ok = (signature[0] == 'P' && signature[1] == 'E' && signature[2] == 0 && signature[3] == 0); + } while (0); + + return ok; +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ + +/* detect object file format from stream + * + * @param istream the input stream + * @return XM_BINUTILS_FORMAT_COFF, XM_BINUTILS_FORMAT_ELF, XM_BINUTILS_FORMAT_MACHO, + * XM_BINUTILS_FORMAT_AR, XM_BINUTILS_FORMAT_PE, XM_BINUTILS_FORMAT_UNKNOWN, or -1 on error + */ +tb_int_t xm_binutils_format_detect(tb_stream_ref_t istream) { + tb_assert_and_check_return_val(istream, -1); + tb_assert_and_check_return_val(tb_stream_offset(istream) == 0, -1); + + tb_int_t format = -1; + do { + tb_byte_t* p = tb_null; + if (!tb_stream_peek(istream, &p, 8)) { + tb_hong_t size = tb_stream_size(istream); + if (size > 0 && size < 8) { + format = XM_BINUTILS_FORMAT_UNKNOWN; + } + break; + } + + if (p[0] == '!' && p[1] == '<' && p[2] == 'a' && + p[3] == 'r' && p[4] == 'c' && p[5] == 'h' && + (p[6] == '>' || p[6] == '\n') && + (p[7] == '\n' || p[7] == '\r')) { + format = XM_BINUTILS_FORMAT_AR; + break; + } + + if (xm_binutils_format_detect_pe(istream, p)) { + format = XM_BINUTILS_FORMAT_PE; + break; + } + + if (p[0] == 0x7f && p[1] == 'E' && p[2] == 'L' && p[3] == 'F') { + format = XM_BINUTILS_FORMAT_ELF; + break; + } + + if (p[0] == 0xfe && p[1] == 0xed && p[2] == 0xfa && + (p[3] == 0xce || p[3] == 0xcf)) { + format = XM_BINUTILS_FORMAT_MACHO; + break; + } + if (p[0] == 0xce && p[1] == 0xfa && p[2] == 0xed && p[3] == 0xfe) { + format = XM_BINUTILS_FORMAT_MACHO; + break; + } + if (p[0] == 0xcf && p[1] == 0xfa && p[2] == 0xed && p[3] == 0xfe) { + format = XM_BINUTILS_FORMAT_MACHO; + break; + } + + tb_uint16_t machine = (tb_uint16_t)((p[1] << 8) | p[0]); + + if (machine == 0x0000) { + tb_uint16_t machine2 = (tb_uint16_t)((p[3] << 8) | p[2]); + if (machine2 == 0xffff) { + format = XM_BINUTILS_FORMAT_COFF; + break; + } + } + + if (machine == XM_BINUTILS_COFF_MACHINE_I386 || + machine == XM_BINUTILS_COFF_MACHINE_AMD64 || + machine == XM_BINUTILS_COFF_MACHINE_ARM || + machine == XM_BINUTILS_COFF_MACHINE_ARM64) { + format = XM_BINUTILS_FORMAT_COFF; + break; + } + + format = XM_BINUTILS_FORMAT_UNKNOWN; + + } while (0); + + return format; +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * lua implementation + */ + +/* get binary file format (auto-detect format) + * + * local format, errors = binutils.format(filepath) + */ +tb_int_t xm_binutils_format(lua_State *lua) { + tb_assert_and_check_return_val(lua, 0); + + // get the binary file path + tb_char_t const *binaryfile = luaL_checkstring(lua, 1); + tb_check_return_val(binaryfile, 0); + + // open file + tb_stream_ref_t istream = tb_stream_init_from_file(binaryfile, TB_FILE_MODE_RO); + if (!istream) { + lua_pushnil(lua); + lua_pushfstring(lua, "format: open %s failed", binaryfile); + return 2; + } + + tb_bool_t ok = tb_false; + do { + if (!tb_stream_open(istream)) { + lua_pushnil(lua); + lua_pushfstring(lua, "format: open %s failed", binaryfile); + break; + } + + tb_int_t format = xm_binutils_format_detect(istream); + if (format < 0) { + lua_pushnil(lua); + lua_pushliteral(lua, "format: cannot detect file format"); + break; + } + + switch (format) { + case XM_BINUTILS_FORMAT_COFF: lua_pushliteral(lua, "coff"); break; + case XM_BINUTILS_FORMAT_ELF: lua_pushliteral(lua, "elf"); break; + case XM_BINUTILS_FORMAT_MACHO: lua_pushliteral(lua, "macho"); break; + case XM_BINUTILS_FORMAT_AR: lua_pushliteral(lua, "ar"); break; + case XM_BINUTILS_FORMAT_PE: lua_pushliteral(lua, "pe"); break; + default: lua_pushliteral(lua, "unknown"); break; + } + + ok = tb_true; + } while (0); + + if (istream) { + tb_stream_exit(istream); + } + return ok ? 1 : 2; +} diff --git a/core/src/xmake/binutils/mslib/readsyms.c b/core/src/xmake/binutils/mslib/readsyms.c index 55857bb58..e314d08f3 100644 --- a/core/src/xmake/binutils/mslib/readsyms.c +++ b/core/src/xmake/binutils/mslib/readsyms.c @@ -298,7 +298,7 @@ tb_bool_t xm_binutils_mslib_read_symbols(tb_stream_ref_t istream, tb_hize_t base tb_hize_t header_offset = current_pos - sizeof(xm_mslib_header_t); // detect format - tb_int_t format = xm_binutils_detect_format(istream); + tb_int_t format = xm_binutils_format_detect(istream); if (format != XM_BINUTILS_FORMAT_UNKNOWN && format != XM_BINUTILS_FORMAT_AR) { // create entry table lua_newtable(lua); diff --git a/core/src/xmake/binutils/prefix.h b/core/src/xmake/binutils/prefix.h index 7df5b55a7..a38eef658 100644 --- a/core/src/xmake/binutils/prefix.h +++ b/core/src/xmake/binutils/prefix.h @@ -48,6 +48,11 @@ #define XM_BINUTILS_PE_NT_SIGNATURE (0x00004550) // "PE\0\0" little endian /* ////////////////////////////////////////////////////////////////////////////////////// + * interfaces + */ +tb_int_t xm_binutils_format_detect(tb_stream_ref_t istream); + +/* ////////////////////////////////////////////////////////////////////////////////////// * inline implementation */ @@ -76,136 +81,6 @@ static __tb_inline__ tb_bool_t xm_binutils_read_magic(tb_stream_ref_t istream, t return ok; } -/* check if it's a PE file from the beginning of stream - * - * @note the stream offset will be preserved by this function - */ -static __tb_inline__ tb_bool_t xm_binutils_detect_pe(tb_stream_ref_t istream, tb_byte_t* first8) { - tb_assert_and_check_return_val(istream && first8, tb_false); - - // check PE/DOS magic ("MZ" or "ZM") and verify NT signature - if (!((first8[0] == 'M' && first8[1] == 'Z') || (first8[0] == 'Z' && first8[1] == 'M'))) { - return tb_false; - } - - tb_bool_t ok = tb_false; - do { - tb_hong_t size = tb_stream_size(istream); - if (size > 0 && size < XM_BINUTILS_PE_DOS_STUB_MIN_SIZE + 4) { - break; - } - - tb_size_t max_peek = 4096; - if (size > 0) { - max_peek = (tb_size_t)tb_min((tb_hize_t)max_peek, (tb_hize_t)size); - } - - tb_byte_t* p = tb_null; - if (!tb_stream_peek(istream, &p, max_peek)) { - break; - } - - tb_uint32_t e_lfanew = (tb_uint32_t)( (tb_uint32_t)p[XM_BINUTILS_PE_DOS_ELFANEW_OFFSET] - | ((tb_uint32_t)p[XM_BINUTILS_PE_DOS_ELFANEW_OFFSET + 1] << 8) - | ((tb_uint32_t)p[XM_BINUTILS_PE_DOS_ELFANEW_OFFSET + 2] << 16) - | ((tb_uint32_t)p[XM_BINUTILS_PE_DOS_ELFANEW_OFFSET + 3] << 24)); - tb_check_break(e_lfanew >= XM_BINUTILS_PE_DOS_STUB_MIN_SIZE); - tb_check_break((tb_size_t)e_lfanew + 4 <= max_peek); - tb_check_break(size <= 0 || (tb_hize_t)e_lfanew + 4 <= (tb_hize_t)size); - - tb_byte_t const* signature = p + (tb_size_t)e_lfanew; - ok = (signature[0] == 'P' && signature[1] == 'E' && signature[2] == 0 && signature[3] == 0); - } while (0); - - return ok; -} - -/* detect object file format from stream - * - * @param istream the input stream - * @return XM_BINUTILS_FORMAT_COFF, XM_BINUTILS_FORMAT_ELF, XM_BINUTILS_FORMAT_MACHO, - * XM_BINUTILS_FORMAT_AR, XM_BINUTILS_FORMAT_PE, XM_BINUTILS_FORMAT_UNKNOWN, or -1 on error - */ -static __tb_inline__ tb_int_t xm_binutils_detect_format(tb_stream_ref_t istream) { - tb_assert_and_check_return_val(istream, -1); - tb_assert_and_check_return_val(tb_stream_offset(istream) == 0, -1); - - tb_int_t format = -1; - do { - // peek first 8 bytes - tb_byte_t* p = tb_null; - if (!tb_stream_peek(istream, &p, 8)) { - tb_hong_t size = tb_stream_size(istream); - if (size > 0 && size < 8) { - format = XM_BINUTILS_FORMAT_UNKNOWN; - } - break; - } - - // check AR archive format first (!<arch>\n) - if (p[0] == '!' && p[1] == '<' && p[2] == 'a' && - p[3] == 'r' && p[4] == 'c' && p[5] == 'h' && - (p[6] == '>' || p[6] == '\n') && - (p[7] == '\n' || p[7] == '\r')) { - format = XM_BINUTILS_FORMAT_AR; - break; - } - - if (xm_binutils_detect_pe(istream, p)) { - format = XM_BINUTILS_FORMAT_PE; - break; - } - - // check ELF magic (0x7f 'E' 'L' 'F') - if (p[0] == 0x7f && p[1] == 'E' && p[2] == 'L' && p[3] == 'F') { - format = XM_BINUTILS_FORMAT_ELF; - break; - } - - // check Mach-O magic - if (p[0] == 0xfe && p[1] == 0xed && p[2] == 0xfa && - (p[3] == 0xce || p[3] == 0xcf)) { - format = XM_BINUTILS_FORMAT_MACHO; // Mach-O 32/64 (big endian) - break; - } - if (p[0] == 0xce && p[1] == 0xfa && p[2] == 0xed && p[3] == 0xfe) { - format = XM_BINUTILS_FORMAT_MACHO; // Mach-O 32 (little endian) - break; - } - if (p[0] == 0xcf && p[1] == 0xfa && p[2] == 0xed && p[3] == 0xfe) { - format = XM_BINUTILS_FORMAT_MACHO; // Mach-O 64 (little endian) - break; - } - - // check COFF (object files start with machine type, not a magic number) - // COFF header: machine (2 bytes) + nsects (2 bytes) + time (4 bytes) + ... - tb_uint16_t machine = (tb_uint16_t)((p[1] << 8) | p[0]); - - // Import header: 0x0000 0xffff - if (machine == 0x0000) { - tb_uint16_t machine2 = (tb_uint16_t)((p[3] << 8) | p[2]); - if (machine2 == 0xffff) { - format = XM_BINUTILS_FORMAT_COFF; - break; - } - } - - if (machine == XM_BINUTILS_COFF_MACHINE_I386 || - machine == XM_BINUTILS_COFF_MACHINE_AMD64 || - machine == XM_BINUTILS_COFF_MACHINE_ARM || - machine == XM_BINUTILS_COFF_MACHINE_ARM64) { - format = XM_BINUTILS_FORMAT_COFF; - break; - } - - // unknown format - format = XM_BINUTILS_FORMAT_UNKNOWN; - - } while (0); - - return format; -} - /* copy data from input stream to output stream * * @param istream the input stream diff --git a/core/src/xmake/binutils/readsyms.c b/core/src/xmake/binutils/readsyms.c index 407ba7399..e29010314 100644 --- a/core/src/xmake/binutils/readsyms.c +++ b/core/src/xmake/binutils/readsyms.c @@ -75,7 +75,7 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) { } // detect format - tb_int_t format = xm_binutils_detect_format(istream); + 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"); @@ -163,4 +163,3 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) { return ok ? 1 : 2; } - diff --git a/core/src/xmake/binutils/rpath.c b/core/src/xmake/binutils/rpath.c index 63754c891..c720141c2 100644 --- a/core/src/xmake/binutils/rpath.c +++ b/core/src/xmake/binutils/rpath.c @@ -74,7 +74,7 @@ tb_int_t xm_binutils_rpath_list(lua_State *lua) { } // detect format - tb_int_t format = xm_binutils_detect_format(istream); + tb_int_t format = xm_binutils_format_detect(istream); if (format < 0) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_list: cannot detect file format"); @@ -142,7 +142,7 @@ tb_int_t xm_binutils_rpath_clean(lua_State *lua) { } // detect format - tb_int_t format = xm_binutils_detect_format(istream); + tb_int_t format = xm_binutils_format_detect(istream); if (format < 0) { lua_pushboolean(lua, tb_false); lua_pushfstring(lua, "rpath_clean: cannot detect file format"); |
