summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-12 23:38:31 +0800
committerruki <[email protected]>2025-12-12 23:38:31 +0800
commitd831ef584b970bcf098920f999c40ab9a686d3b3 (patch)
tree7e01b67bcf86926bf823592461122904a263fd35
parent97c17dc338a66bbbae36eef59c4d4ca537bff8ec (diff)
fix coff/deplibs
-rw-r--r--core/src/xmake/binutils/coff/deplibs.c81
-rw-r--r--core/src/xmake/binutils/coff/prefix.h4
-rw-r--r--core/src/xmake/binutils/deplibs.c34
-rw-r--r--core/src/xmake/binutils/prefix.h6
4 files changed, 103 insertions, 22 deletions
diff --git a/core/src/xmake/binutils/coff/deplibs.c b/core/src/xmake/binutils/coff/deplibs.c
index 40d9d2823..1139d1359 100644
--- a/core/src/xmake/binutils/coff/deplibs.c
+++ b/core/src/xmake/binutils/coff/deplibs.c
@@ -55,6 +55,47 @@ tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offse
return tb_false;
}
+ // try to get import directory rva from optional header
+ tb_uint32_t import_rva = 0;
+ if (header.opthdr > 0) {
+ // save pos
+ tb_hize_t saved_pos = tb_stream_offset(istream);
+
+ // seek to optional header
+ if (tb_stream_seek(istream, base_offset + sizeof(xm_coff_header_t))) {
+ tb_uint16_t magic = 0;
+ if (tb_stream_bread(istream, (tb_byte_t*)&magic, 2)) {
+ // magic is little endian
+ magic = tb_bits_le_to_ne_u16(magic);
+ // tb_printf("magic: %x\n", magic);
+
+ tb_uint32_t data_dir_offset = 0;
+ if (magic == XM_PE32_MAGIC) {
+ data_dir_offset = 96;
+ } else if (magic == XM_PE32P_MAGIC) {
+ data_dir_offset = 112;
+ }
+
+ // check if optional header is large enough to contain import directory entry (index 1)
+ // export(0) + import(1) -> 2 entries -> 16 bytes
+ // tb_printf("opthdr: %d, data_dir_offset: %d\n", header.opthdr, data_dir_offset);
+ if (data_dir_offset != 0 && header.opthdr >= data_dir_offset + 16) {
+ // seek to Import Directory (Index 1)
+ // Data Directory Array starts at optional_header_start + data_dir_offset
+ // Index 1 is at + 8 bytes (sizeof(IMAGE_DATA_DIRECTORY) * 1)
+ if (tb_stream_seek(istream, base_offset + sizeof(xm_coff_header_t) + data_dir_offset + 8)) {
+ if (tb_stream_bread(istream, (tb_byte_t*)&import_rva, 4)) {
+ import_rva = tb_bits_le_to_ne_u32(import_rva);
+ // tb_printf("import_rva: %x\n", import_rva);
+ }
+ }
+ }
+ }
+ }
+ // restore pos
+ tb_stream_seek(istream, saved_pos);
+ }
+
tb_size_t result_count = 0;
for (tb_uint16_t i = 0; i < header.nsects; i++) {
xm_coff_section_t section;
@@ -63,20 +104,27 @@ tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offse
}
// check if it is .idata section (import directory table)
- // section name is 8 bytes, null-padded if shorter, or starts with '/' for long names
- // standard import section is named ".idata"
- if (tb_strncmp(section.name, ".idata", 6) == 0) {
+ tb_bool_t found_idt = tb_false;
+ tb_uint32_t idt_offset = 0;
+ if (import_rva != 0) {
+ // check if import rva is in this section
+ if (import_rva >= section.vaddr && import_rva < section.vaddr + section.vsize) {
+ idt_offset = section.ofs + (import_rva - section.vaddr);
+ found_idt = tb_true;
+ }
+ } else {
+ // fallback to check section name
+ if (tb_strncmp(section.name, ".idata", 6) == 0) {
+ idt_offset = section.ofs;
+ found_idt = tb_true;
+ }
+ }
+
+ if (found_idt) {
// read import directory table
// The .idata section contains the Import Directory Table.
// Each entry is 20 bytes (IMAGE_IMPORT_DESCRIPTOR).
// The table ends with a null entry.
-
- // The .idata section usually contains multiple parts.
- // We need to parse the Import Directory Table which is typically at the beginning of the section data.
- // However, the section data might be raw data at 'ofs'
-
- // The VirtualAddress (vaddr) in the section header is the RVA where the section is loaded.
- // The PointerToRawData (ofs) is the file offset.
// We need to iterate over IMAGE_IMPORT_DESCRIPTOR entries.
// struct IMAGE_IMPORT_DESCRIPTOR {
@@ -87,14 +135,7 @@ tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offse
// DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
// };
- // We need to map RVA to file offset.
- // RVA = vaddr + offset_in_section
- // FileOffset = ofs + offset_in_section
- // So, offset_in_section = RVA - vaddr
- // FileOffset = ofs + (RVA - vaddr)
-
- tb_uint32_t import_descriptors_offset = section.ofs;
- if (!tb_stream_seek(istream, base_offset + import_descriptors_offset)) {
+ if (!tb_stream_seek(istream, idt_offset)) {
return tb_false;
}
@@ -115,6 +156,8 @@ tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offse
if (original_first_thunk == 0 && name_rva == 0) {
break;
}
+
+ name_rva = tb_bits_le_to_ne_u32(name_rva);
if (name_rva != 0) {
// map RVA to file offset to read the name
@@ -155,7 +198,7 @@ tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offse
}
if (name_file_offset != 0) {
- if (tb_stream_seek(istream, base_offset + name_file_offset)) {
+ if (tb_stream_seek(istream, name_file_offset)) {
tb_char_t dll_name[256];
tb_size_t pos = 0;
tb_byte_t c;
diff --git a/core/src/xmake/binutils/coff/prefix.h b/core/src/xmake/binutils/coff/prefix.h
index 6b009b056..f62ff547d 100644
--- a/core/src/xmake/binutils/coff/prefix.h
+++ b/core/src/xmake/binutils/coff/prefix.h
@@ -34,6 +34,10 @@
#define XM_COFF_MACHINE_ARM 0x01c0
#define XM_COFF_MACHINE_ARM64 0xaa64
+/* PE Optional Header Magic */
+#define XM_PE32_MAGIC 0x10b
+#define XM_PE32P_MAGIC 0x20b
+
// 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
diff --git a/core/src/xmake/binutils/deplibs.c b/core/src/xmake/binutils/deplibs.c
index 9ca621f1a..289e656a0 100644
--- a/core/src/xmake/binutils/deplibs.c
+++ b/core/src/xmake/binutils/deplibs.c
@@ -91,11 +91,32 @@ tb_int_t xm_binutils_deplibs(lua_State *lua) {
lua_pushfstring(lua, "deplibs: failed to parse COFF");
break;
}
- } else if (format == XM_BINUTILS_FORMAT_ELF) {
- if (!xm_binutils_elf_deplibs(istream, 0, lua)) {
+ } else if (format == XM_BINUTILS_FORMAT_PE) {
+ // seek to e_lfanew
+ if (!tb_stream_seek(istream, 0x3c)) {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
- lua_pushfstring(lua, "deplibs: failed to parse ELF");
+ lua_pushfstring(lua, "deplibs: failed to seek to e_lfanew");
+ break;
+ }
+
+ // read e_lfanew
+ tb_uint32_t e_lfanew = 0;
+ 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");
+ break;
+ }
+
+ // e_lfanew is little endian
+ e_lfanew = tb_bits_le_to_ne_u32(e_lfanew);
+
+ // call coff deplibs with offset = e_lfanew + 4 (skip PE signature)
+ 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");
break;
}
} else if (format == XM_BINUTILS_FORMAT_MACHO) {
@@ -105,6 +126,13 @@ tb_int_t xm_binutils_deplibs(lua_State *lua) {
lua_pushfstring(lua, "deplibs: 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");
+ break;
+ }
} else {
lua_pop(lua, 1); // pop table
lua_pushboolean(lua, tb_false);
diff --git a/core/src/xmake/binutils/prefix.h b/core/src/xmake/binutils/prefix.h
index 492ed691c..64c7cd80f 100644
--- a/core/src/xmake/binutils/prefix.h
+++ b/core/src/xmake/binutils/prefix.h
@@ -33,6 +33,7 @@
#define XM_BINUTILS_FORMAT_ELF 2
#define XM_BINUTILS_FORMAT_MACHO 3
#define XM_BINUTILS_FORMAT_AR 4
+#define XM_BINUTILS_FORMAT_PE 5
#define XM_BINUTILS_FORMAT_UNKNOWN 0
/* COFF machine types (for format detection) */
@@ -93,6 +94,11 @@ static __tb_inline__ tb_int_t xm_binutils_detect_format(tb_stream_ref_t istream)
return XM_BINUTILS_FORMAT_AR;
}
+ // check PE/DOS magic (0x5A4D 'M' 'Z')
+ if (p[0] == 'M' && p[1] == 'Z') {
+ return XM_BINUTILS_FORMAT_PE;
+ }
+
// check ELF magic (0x7f 'E' 'L' 'F')
if (p[0] == 0x7f && p[1] == 'E' && p[2] == 'L' && p[3] == 'F') {
return XM_BINUTILS_FORMAT_ELF;