summaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-11 23:47:51 +0800
committerruki <[email protected]>2025-12-12 09:00:45 +0800
commit37c29cafa18e56d8b74b012665983c6ef132e28f (patch)
tree1994a67a32213bc22d9678b666a3d42729c3bbf6 /core/src
parent334605bbe1bbe5b6b00b920b1228ef26b6288939 (diff)
readsyms from .lib
Diffstat (limited to 'core/src')
-rw-r--r--core/src/xmake/binutils/mslib/readsyms.c211
-rw-r--r--core/src/xmake/binutils/readsyms.c28
2 files changed, 235 insertions, 4 deletions
diff --git a/core/src/xmake/binutils/mslib/readsyms.c b/core/src/xmake/binutils/mslib/readsyms.c
new file mode 100644
index 000000000..74139ae5c
--- /dev/null
+++ b/core/src/xmake/binutils/mslib/readsyms.c
@@ -0,0 +1,211 @@
+/*!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 "mslib_readsyms"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * forward declarations
+ */
+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);
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+/* read symbols from MSVC lib archive
+ *
+ * @param istream the input stream
+ * @param base_offset the base offset
+ * @param lua the lua state
+ * @return tb_true on success, tb_false on failure
+ */
+tb_bool_t xm_binutils_mslib_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);
+
+ // check magic (!<arch>\n)
+ if (!xm_binutils_mslib_check_magic(istream)) {
+ return tb_false;
+ }
+
+ tb_bool_t ok = tb_true;
+ tb_size_t object_count = 0;
+ tb_char_t* longnames = tb_null;
+ tb_size_t longnames_size = 0;
+
+ // iterate through members
+ while (ok) {
+ // read header
+ xm_mslib_header_t header;
+ if (!tb_stream_bread(istream, (tb_byte_t*)&header, sizeof(header))) {
+ // end of file
+ break;
+ }
+
+ // parse member size
+ tb_int64_t member_size = xm_binutils_mslib_parse_decimal(header.size, 10);
+ if (member_size < 0) {
+ ok = tb_false;
+ break;
+ }
+
+ // parse member name
+ tb_char_t member_name[256] = {0};
+ tb_bool_t is_longname_table = tb_false;
+
+ if (header.name[0] == '/') {
+ if (header.name[1] == '/') {
+ // long name table (//)
+ is_longname_table = tb_true;
+ } else if (tb_isdigit(header.name[1])) {
+ // offset into long name table (/123)
+ tb_int64_t offset = xm_binutils_mslib_parse_decimal(header.name + 1, 15);
+ if (offset >= 0 && (tb_size_t)offset < longnames_size) {
+ // copy from longnames
+ // names in longnames are null-terminated
+ tb_strlcpy(member_name, longnames + offset, sizeof(member_name));
+ }
+ } else {
+ // symbol table or other special member (/)
+ // usually symbol table is just "/"
+ tb_strlcpy(member_name, "/", sizeof(member_name));
+ }
+ } else {
+ // short name, ends with /
+ tb_size_t i = 0;
+ for (i = 0; i < 16 && header.name[i] != '/'; i++) {
+ member_name[i] = header.name[i];
+ }
+ member_name[i] = '\0';
+ }
+
+ if (is_longname_table) {
+ if (longnames) tb_free(longnames);
+ longnames = (tb_char_t*)tb_malloc_bytes((tb_size_t)member_size + 1);
+ if (!longnames || !tb_stream_bread(istream, (tb_byte_t*)longnames, (tb_size_t)member_size)) {
+ ok = tb_false;
+ break;
+ }
+ longnames[member_size] = '\0';
+ longnames_size = (tb_size_t)member_size;
+
+ // align
+ if (member_size % 2) {
+ if (!tb_stream_skip(istream, 1)) {
+ ok = tb_false;
+ break;
+ }
+ }
+ continue;
+ }
+
+ // check if we should process
+ // skip empty names, symbol tables (/), long name table (//) - handled above,
+ // and __.SYMDEF (SysV/BSD style symbol table, just in case)
+ if (member_name[0] == '\0' || tb_strcmp(member_name, "/") == 0 || tb_strcmp(member_name, "//") == 0 ||
+ tb_strncmp(member_name, "__.SYMDEF", 9) == 0) {
+
+ // skip member data
+ if (!tb_stream_skip(istream, member_size)) {
+ ok = tb_false;
+ break;
+ }
+ // align
+ if (member_size % 2) {
+ if (!tb_stream_skip(istream, 1)) {
+ ok = tb_false;
+ break;
+ }
+ }
+ continue;
+ }
+
+ // save current position
+ tb_hize_t current_pos = tb_stream_offset(istream);
+
+ // detect format
+ tb_int_t format = xm_binutils_detect_format(istream);
+ if (format != XM_BINUTILS_FORMAT_UNKNOWN && format != XM_BINUTILS_FORMAT_AR) {
+ // create entry table
+ lua_newtable(lua);
+
+ // object name
+ lua_pushstring(lua, "objectfile");
+ lua_pushstring(lua, member_name);
+ lua_settable(lua, -3);
+
+ // symbols
+ lua_pushstring(lua, "symbols");
+ tb_bool_t read_ok = tb_false;
+ if (format == XM_BINUTILS_FORMAT_COFF) {
+ read_ok = xm_binutils_coff_read_symbols(istream, current_pos, lua);
+ } else if (format == XM_BINUTILS_FORMAT_ELF) {
+ 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);
+ }
+
+ if (read_ok) {
+ lua_settable(lua, -3);
+ lua_rawseti(lua, -2, (int)(++object_count));
+ } else {
+ lua_pop(lua, 2); // pop symbols key and entry table
+ }
+ }
+
+ // skip to next member
+ tb_hize_t member_data_read = tb_stream_offset(istream) - current_pos;
+ tb_hize_t remaining_size = (tb_hize_t)member_size - member_data_read;
+
+ if (remaining_size > 0) {
+ if (!tb_stream_skip(istream, remaining_size)) {
+ ok = tb_false;
+ break;
+ }
+ } else if (remaining_size < 0) {
+ if (!tb_stream_seek(istream, current_pos + (tb_hize_t)member_size)) {
+ ok = tb_false;
+ break;
+ }
+ }
+
+ // align to 2-byte boundary
+ if (member_size % 2) {
+ if (!tb_stream_skip(istream, 1)) {
+ ok = tb_false;
+ break;
+ }
+ }
+ }
+
+ if (longnames) tb_free(longnames);
+ return ok;
+}
diff --git a/core/src/xmake/binutils/readsyms.c b/core/src/xmake/binutils/readsyms.c
index 7f7c798c4..145488c93 100644
--- a/core/src/xmake/binutils/readsyms.c
+++ b/core/src/xmake/binutils/readsyms.c
@@ -40,6 +40,7 @@ extern tb_bool_t xm_binutils_coff_read_symbols(tb_stream_ref_t istream, tb_hize_
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_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);
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
@@ -87,10 +88,29 @@ tb_int_t xm_binutils_readsyms(lua_State *lua) {
// read symbols based on format
if (format == XM_BINUTILS_FORMAT_AR) {
// AR archive (.a or .lib)
- if (!xm_binutils_ar_read_symbols(istream, 0, lua)) {
- lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "readsyms: read AR archive symbols failed");
- break;
+ tb_bool_t is_mslib = tb_false;
+ if (objectfile) {
+ tb_size_t len = tb_strlen(objectfile);
+ if (len > 4 && tb_stricmp(objectfile + len - 4, ".lib") == 0) {
+ is_mslib = tb_true;
+ }
+ }
+
+ if (is_mslib) {
+ if (!xm_binutils_mslib_read_symbols(istream, 0, 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");
+ 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");
+ break;
+ }
}
} else {
// single object file (COFF, ELF, Mach-O)