diff options
| author | ruki <[email protected]> | 2025-12-12 23:38:31 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2025-12-12 23:38:31 +0800 |
| commit | d831ef584b970bcf098920f999c40ab9a686d3b3 (patch) | |
| tree | 7e01b67bcf86926bf823592461122904a263fd35 | |
| parent | 97c17dc338a66bbbae36eef59c4d4ca537bff8ec (diff) | |
fix coff/deplibs
| -rw-r--r-- | core/src/xmake/binutils/coff/deplibs.c | 81 | ||||
| -rw-r--r-- | core/src/xmake/binutils/coff/prefix.h | 4 | ||||
| -rw-r--r-- | core/src/xmake/binutils/deplibs.c | 34 | ||||
| -rw-r--r-- | core/src/xmake/binutils/prefix.h | 6 |
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; |
