read_util.c (2852B)
1 /* Shared PE/COFF reader primitives — see read_util.h. */ 2 3 #include "obj/coff/read_util.h" 4 5 #include <string.h> 6 7 #include "obj/obj.h" /* SecKind / SecFlag enums */ 8 9 int coff_rva_to_offset(const u8* shdrs, u16 nsec, u32 rva, size_t len, 10 u64* off_out) { 11 for (u16 i = 0; i < nsec; ++i) { 12 const u8* sh = shdrs + (u64)i * COFF_SECTION_HEADER_SIZE; 13 u32 vsize = coff_rd_u32(sh + 8); 14 u32 vaddr = coff_rd_u32(sh + 12); 15 u32 raw_size = coff_rd_u32(sh + 16); 16 u32 raw_ptr = coff_rd_u32(sh + 20); 17 /* Some linkers leave VirtualSize == 0 in objects; use raw_size as 18 * a fallback so we still resolve RVAs in well-formed images. */ 19 u32 span = vsize ? vsize : raw_size; 20 if (rva >= vaddr && rva < vaddr + span) { 21 u64 delta = (u64)(rva - vaddr); 22 if (delta >= raw_size) return 0; /* RVA past on-disk data */ 23 u64 off = (u64)raw_ptr + delta; 24 if (off >= len) return 0; 25 *off_out = off; 26 return 1; 27 } 28 } 29 return 0; 30 } 31 32 u32 coff_read_cstr(const u8* data, size_t len, u64 off, const char** out) { 33 if (off >= len) { 34 *out = ""; 35 return 0; 36 } 37 const char* s = (const char*)(data + off); 38 u64 max = (u64)len - off; 39 u64 n = 0; 40 while (n < max && s[n] != '\0') ++n; 41 if (n == max) { 42 *out = ""; 43 return 0; 44 } /* unterminated */ 45 *out = s; 46 return (u32)n; 47 } 48 49 u16 coff_sec_kind(const char* name, u32 nlen, u32 ch) { 50 if (ch & IMAGE_SCN_CNT_UNINITIALIZED_DATA) return SEC_BSS; 51 if (ch & IMAGE_SCN_CNT_CODE) return SEC_TEXT; 52 if (ch & IMAGE_SCN_MEM_EXECUTE) return SEC_TEXT; 53 if (nlen >= 7 && memcmp(name, ".debug_", 7) == 0) return SEC_DEBUG; 54 /* The MS toolchain spells DWARF section names with a leading ".debug$" 55 * (CodeView) — keep ELF-style ".debug_" detection but also treat the 56 * MS form as debug. */ 57 if (nlen >= 7 && memcmp(name, ".debug$", 7) == 0) return SEC_DEBUG; 58 if (ch & IMAGE_SCN_CNT_INITIALIZED_DATA) { 59 if (ch & IMAGE_SCN_MEM_WRITE) return SEC_DATA; 60 return SEC_RODATA; 61 } 62 return SEC_OTHER; 63 } 64 65 u16 coff_sec_flags(const char* name, u32 nlen, u32 ch) { 66 u16 f = 0; 67 if (ch & IMAGE_SCN_MEM_READ) f |= SF_ALLOC; 68 if (ch & IMAGE_SCN_MEM_EXECUTE) f |= SF_EXEC; 69 if (ch & IMAGE_SCN_MEM_WRITE) f |= SF_WRITE; 70 if (ch & IMAGE_SCN_LNK_COMDAT) f |= SF_GROUP; 71 /* TLS sections in PE are spelled ".tls$<suffix>" (e.g. ".tls$", ".tls$ZZZ"). 72 * There is no characteristics bit for TLS — detection is name-based. */ 73 if (nlen >= 5 && memcmp(name, ".tls$", 5) == 0) f |= SF_TLS; 74 if (nlen == 4 && memcmp(name, ".tls", 4) == 0) f |= SF_TLS; 75 return f; 76 } 77 78 /* Bits 20..23 of Characteristics encode alignment as (log2(align)+1). 79 * 0 means "default"; we collapse to align=1 for round-trip purposes. */ 80 u32 coff_sec_align(u32 ch) { 81 u32 n = (ch & IMAGE_SCN_ALIGN_MASK) >> 20; 82 if (n == 0) return 1; 83 return 1u << (n - 1u); 84 }