summaryrefslogtreecommitdiff
path: root/core/src/xmake/binutils/coff
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-14 23:23:38 +0800
committerruki <[email protected]>2025-12-14 23:23:38 +0800
commit65d966f76661b4756a5154a44155a87ff7cdd0b0 (patch)
treea791b0dba58071633b38e405c41450c863fe8dee /core/src/xmake/binutils/coff
parente9bf831cc47fa3f4c45d1fee4b6db29dae60319b (diff)
improve coff deplibs
Diffstat (limited to 'core/src/xmake/binutils/coff')
-rw-r--r--core/src/xmake/binutils/coff/deplibs.c156
-rw-r--r--core/src/xmake/binutils/coff/prefix.h80
2 files changed, 143 insertions, 93 deletions
diff --git a/core/src/xmake/binutils/coff/deplibs.c b/core/src/xmake/binutils/coff/deplibs.c
index 44809a535..969702e98 100644
--- a/core/src/xmake/binutils/coff/deplibs.c
+++ b/core/src/xmake/binutils/coff/deplibs.c
@@ -49,72 +49,78 @@ tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offse
return tb_false;
}
- // read section headers
- tb_hize_t section_offset = base_offset + sizeof(xm_coff_header_t) + header.opthdr;
- if (!tb_stream_seek(istream, section_offset)) {
- return tb_false;
- }
-
- // try to get import directory rva from optional header
+ // read optional header and import rva
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_uint32_t data_dir_offset = 0;
+ // save current offset
+ tb_hize_t opt_offset = tb_stream_offset(istream);
+
+ // read magic
+ tb_uint16_t magic = 0;
+ if (tb_stream_bread(istream, (tb_byte_t*)&magic, sizeof(magic))) {
+ // seek back
+ if (tb_stream_seek(istream, opt_offset)) {
if (magic == XM_PE32_MAGIC) {
- data_dir_offset = 96;
+ xm_pe32_opt_header_t opt_header = {0};
+ if (tb_stream_bread(istream, (tb_byte_t*)&opt_header, tb_min(sizeof(opt_header), header.opthdr))) {
+ if (opt_header.number_of_rva_and_sizes > 1) {
+ import_rva = opt_header.data_directory[1].vaddr;
+ }
+ }
} 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
- */
- 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);
+ xm_pe32p_opt_header_t opt_header = {0};
+ if (tb_stream_bread(istream, (tb_byte_t*)&opt_header, tb_min(sizeof(opt_header), header.opthdr))) {
+ if (opt_header.number_of_rva_and_sizes > 1) {
+ import_rva = opt_header.data_directory[1].vaddr;
}
}
}
}
}
- // restore pos
- tb_stream_seek(istream, saved_pos);
}
+ // read section headers
+ xm_coff_section_t* sections = tb_null;
+ if (header.nsects > 0) {
+ sections = tb_nalloc_type(header.nsects, xm_coff_section_t);
+ if (sections) {
+ tb_hize_t section_offset = base_offset + sizeof(xm_coff_header_t) + header.opthdr;
+ if (tb_stream_seek(istream, section_offset)) {
+ if (!tb_stream_bread(istream, (tb_byte_t*)sections, header.nsects * sizeof(xm_coff_section_t))) {
+ tb_free(sections);
+ sections = tb_null;
+ }
+ } else {
+ tb_free(sections);
+ sections = tb_null;
+ }
+ }
+ }
+
+ if (!sections) {
+ if (header.nsects > 0) return tb_false;
+ lua_newtable(lua);
+ return tb_true;
+ }
+
+ lua_newtable(lua);
tb_size_t result_count = 0;
for (tb_uint16_t i = 0; i < header.nsects; i++) {
- xm_coff_section_t section;
- if (!tb_stream_bread(istream, (tb_byte_t*)&section, sizeof(section))) {
- return tb_false;
- }
+ xm_coff_section_t* section = &sections[i];
// check if it is .idata section (import directory table)
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);
+ 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;
+ if (tb_strncmp(section->name, ".idata", 6) == 0) {
+ idt_offset = section->ofs;
found_idt = tb_true;
}
}
@@ -137,67 +143,37 @@ tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offse
*/
if (!tb_stream_seek(istream, idt_offset)) {
- return tb_false;
+ break;
}
while (1) {
- tb_uint32_t original_first_thunk;
- tb_uint32_t time_date_stamp;
- tb_uint32_t forwarder_chain;
- tb_uint32_t name_rva;
- tb_uint32_t first_thunk;
-
- if (!tb_stream_bread(istream, (tb_byte_t*)&original_first_thunk, 4)) { break; }
- if (!tb_stream_bread(istream, (tb_byte_t*)&time_date_stamp, 4)) { break; }
- if (!tb_stream_bread(istream, (tb_byte_t*)&forwarder_chain, 4)) { break; }
- if (!tb_stream_bread(istream, (tb_byte_t*)&name_rva, 4)) { break; }
- if (!tb_stream_bread(istream, (tb_byte_t*)&first_thunk, 4)) { break; }
+ xm_coff_import_directory_table_t entry;
+ if (!tb_stream_bread(istream, (tb_byte_t*)&entry, sizeof(entry))) {
+ break;
+ }
// check for null entry (end of table)
- if (original_first_thunk == 0 && name_rva == 0) {
+ if (entry.original_first_thunk == 0 && entry.name_rva == 0) {
break;
}
- name_rva = tb_bits_le_to_ne_u32(name_rva);
+ tb_uint32_t name_rva = tb_bits_le_to_ne_u32(entry.name_rva);
if (name_rva != 0) {
/* map RVA to file offset to read the name
* We need to find the section that contains this RVA.
- * Since we are iterating sections, we might need to seek back to read section headers again or cache them.
- * For simplicity, we assume the name string is within the same .idata section or we can find it by scanning sections.
- */
-
- /* To do this correctly, we should scan all sections to find which one contains the RVA.
- * But here we are inside a loop iterating sections.
- * We can save current position and iterate sections from the beginning (or cached) to find the RVA.
*/
- // Optimization: usually the name is in the same .idata section or a nearby .rdata section.
-
tb_hize_t saved_pos_inner = tb_stream_offset(istream);
-
- // Find the section containing name_rva
tb_uint32_t name_file_offset = 0;
- // check current section first
- if (name_rva >= section.vaddr && name_rva < section.vaddr + section.vsize) {
- name_file_offset = section.ofs + (name_rva - section.vaddr);
- } else {
- // Scan all sections to find the RVA
- tb_hize_t saved_pos_sections = tb_stream_offset(istream);
- if (tb_stream_seek(istream, section_offset)) {
- for (tb_uint16_t k = 0; k < header.nsects; k++) {
- xm_coff_section_t s;
- if (!tb_stream_bread(istream, (tb_byte_t*)&s, sizeof(s))) {
- break;
- }
- if (name_rva >= s.vaddr && name_rva < s.vaddr + s.vsize) {
- name_file_offset = s.ofs + (name_rva - s.vaddr);
- break;
- }
- }
+ // Find the section containing name_rva
+ for (tb_uint16_t k = 0; k < header.nsects; k++) {
+ xm_coff_section_t* s = &sections[k];
+ if (name_rva >= s->vaddr && name_rva < s->vaddr + s->vsize) {
+ name_file_offset = s->ofs + (name_rva - s->vaddr);
+ break;
}
- tb_stream_seek(istream, saved_pos_sections); // restore to current descriptor
}
if (name_file_offset != 0) {
@@ -213,16 +189,10 @@ tb_bool_t xm_binutils_coff_deplibs(tb_stream_ref_t istream, tb_hize_t base_offse
tb_stream_seek(istream, saved_pos_inner);
}
}
- /* We found .idata and processed it. Usually there is only one import table.
- * But we should continue just in case or break?
- * Typically break is enough after processing the import table.
- */
break;
}
}
- if (result_count == 0) {
- lua_newtable(lua);
- }
+ if (sections) tb_free(sections);
return tb_true;
}
diff --git a/core/src/xmake/binutils/coff/prefix.h b/core/src/xmake/binutils/coff/prefix.h
index f991ac26d..8017beeff 100644
--- a/core/src/xmake/binutils/coff/prefix.h
+++ b/core/src/xmake/binutils/coff/prefix.h
@@ -59,6 +59,86 @@ typedef struct __xm_coff_header_t {
tb_uint16_t flags;
} __tb_packed__ xm_coff_header_t;
+typedef struct __xm_pe32_data_directory_t {
+ tb_uint32_t vaddr;
+ tb_uint32_t size;
+} __tb_packed__ xm_pe32_data_directory_t;
+
+typedef struct __xm_pe32_opt_header_t {
+ tb_uint16_t magic;
+ tb_uint8_t major_linker_version;
+ tb_uint8_t minor_linker_version;
+ tb_uint32_t size_of_code;
+ tb_uint32_t size_of_initialized_data;
+ tb_uint32_t size_of_uninitialized_data;
+ tb_uint32_t address_of_entry_point;
+ tb_uint32_t base_of_code;
+ tb_uint32_t base_of_data;
+ tb_uint32_t image_base;
+ tb_uint32_t section_alignment;
+ tb_uint32_t file_alignment;
+ tb_uint16_t major_operating_system_version;
+ tb_uint16_t minor_operating_system_version;
+ tb_uint16_t major_image_version;
+ tb_uint16_t minor_image_version;
+ tb_uint16_t major_subsystem_version;
+ tb_uint16_t minor_subsystem_version;
+ tb_uint32_t win32_version_value;
+ tb_uint32_t size_of_image;
+ tb_uint32_t size_of_headers;
+ tb_uint32_t checksum;
+ tb_uint16_t subsystem;
+ tb_uint16_t dll_characteristics;
+ tb_uint32_t size_of_stack_reserve;
+ tb_uint32_t size_of_stack_commit;
+ tb_uint32_t size_of_heap_reserve;
+ tb_uint32_t size_of_heap_commit;
+ tb_uint32_t loader_flags;
+ tb_uint32_t number_of_rva_and_sizes;
+ xm_pe32_data_directory_t data_directory[16];
+} __tb_packed__ xm_pe32_opt_header_t;
+
+typedef struct __xm_pe32p_opt_header_t {
+ tb_uint16_t magic;
+ tb_uint8_t major_linker_version;
+ tb_uint8_t minor_linker_version;
+ tb_uint32_t size_of_code;
+ tb_uint32_t size_of_initialized_data;
+ tb_uint32_t size_of_uninitialized_data;
+ tb_uint32_t address_of_entry_point;
+ tb_uint32_t base_of_code;
+ tb_uint64_t image_base;
+ tb_uint32_t section_alignment;
+ tb_uint32_t file_alignment;
+ tb_uint16_t major_operating_system_version;
+ tb_uint16_t minor_operating_system_version;
+ tb_uint16_t major_image_version;
+ tb_uint16_t minor_image_version;
+ tb_uint16_t major_subsystem_version;
+ tb_uint16_t minor_subsystem_version;
+ tb_uint32_t win32_version_value;
+ tb_uint32_t size_of_image;
+ tb_uint32_t size_of_headers;
+ tb_uint32_t checksum;
+ tb_uint16_t subsystem;
+ tb_uint16_t dll_characteristics;
+ tb_uint64_t size_of_stack_reserve;
+ tb_uint64_t size_of_stack_commit;
+ tb_uint64_t size_of_heap_reserve;
+ tb_uint64_t size_of_heap_commit;
+ tb_uint32_t loader_flags;
+ tb_uint32_t number_of_rva_and_sizes;
+ xm_pe32_data_directory_t data_directory[16];
+} __tb_packed__ xm_pe32p_opt_header_t;
+
+typedef struct __xm_coff_import_directory_table_t {
+ tb_uint32_t original_first_thunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
+ tb_uint32_t time_date_stamp; // 0 if not bound, -1 if bound, and real date\time stamp in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) O.W. date/time stamp of DLL bound to (Old BIND)
+ tb_uint32_t forwarder_chain; // -1 if no forwarders
+ tb_uint32_t name_rva; // RVA to name
+ tb_uint32_t first_thunk; // RVA to IAT (if bound this IAT has actual addresses)
+} __tb_packed__ xm_coff_import_directory_table_t;
+
typedef struct __xm_coff_import_header_t {
tb_uint16_t sig1; // 0
tb_uint16_t sig2; // 0xffff