coff.h (23150B)
1 /* PE/COFF wire-format constants, structs, and per-arch reloc translators 2 * shared between obj/coff_emit.c, obj/coff_read.c, and link/link_coff.c 3 * (none of which exist yet). 4 * 5 * Private to src/. The public ObjBuilder/Linker surface is format-neutral 6 * (obj/obj.h, link/link.h); the PE/COFF spelling of those abstractions 7 * only exists inside libkit. 8 * 9 * Scope: 64-bit little-endian only — IMAGE_FILE_MACHINE_AMD64 (x86_64) 10 * and IMAGE_FILE_MACHINE_ARM64 (aarch64). 32-bit (i386 win32) and 11 * big-endian variants are out of scope. The per-arch reloc mapping is 12 * split across coff_reloc_<arch>.c, mirroring the ELF arrangement; 13 * emit_coff and the linker dispatch to the right translator by 14 * Compiler.target.arch. */ 15 16 #ifndef KIT_OBJ_COFF_H 17 #define KIT_OBJ_COFF_H 18 19 #include <kit/core.h> 20 21 #include "core/bytes.h" 22 #include "core/core.h" 23 #include "obj/obj.h" 24 25 /* ---- file header (IMAGE_FILE_HEADER) ---- 26 * On-disk: 20 bytes, little-endian, no padding. */ 27 #define COFF_FILE_HEADER_SIZE 20u 28 29 typedef struct ImageFileHeader { 30 u16 Machine; /* IMAGE_FILE_MACHINE_* */ 31 u16 NumberOfSections; 32 u32 TimeDateStamp; /* zero for reproducible builds */ 33 u32 PointerToSymbolTable; /* file offset, or 0 if no symtab */ 34 u32 NumberOfSymbols; /* counts aux records too */ 35 u16 SizeOfOptionalHeader; /* 0 for .obj, 240 for PE32+ image */ 36 u16 Characteristics; /* IMAGE_FILE_* */ 37 } ImageFileHeader; 38 39 /* Machine types. Only AMD64 and ARM64 are emitted/read by kit; the 40 * rest are listed for completeness so readers can give a useful 41 * "unsupported machine" diagnostic instead of "unknown machine". */ 42 #define IMAGE_FILE_MACHINE_UNKNOWN 0x0000u 43 #define IMAGE_FILE_MACHINE_AMD64 0x8664u /* x86_64, kit supports */ 44 #define IMAGE_FILE_MACHINE_ARM64 0xAA64u /* aarch64, kit supports */ 45 #define IMAGE_FILE_MACHINE_ARM64EC \ 46 0xA641u /* ARM64EC — readers alias \ 47 * to AArch64 (encoding is \ 48 * identical, only ABI \ 49 * differs). llvm-mingw's \ 50 * compiler-rt builtins ship \ 51 * as ARM64EC objects. */ 52 /* Not supported by kit (here for diagnostic recognition only): */ 53 #define IMAGE_FILE_MACHINE_I386 0x014Cu 54 #define IMAGE_FILE_MACHINE_ARM 0x01C0u 55 #define IMAGE_FILE_MACHINE_ARMNT 0x01C4u 56 #define IMAGE_FILE_MACHINE_IA64 0x0200u 57 #define IMAGE_FILE_MACHINE_RISCV64 0x5064u 58 59 /* Characteristics flags (subset kit handles). */ 60 #define IMAGE_FILE_RELOCS_STRIPPED 0x0001u 61 #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002u 62 #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020u 63 #define IMAGE_FILE_DEBUG_STRIPPED 0x0200u 64 #define IMAGE_FILE_DLL 0x2000u 65 66 /* ---- DOS header + PE signature ---- 67 * kit only emits a minimal DOS stub for executable images: 'MZ' 68 * magic and the e_lfanew offset pointing at "PE\0\0". The remaining 69 * legacy fields are zeroed but kept named for clarity. The DOS stub 70 * program (typically prints "This program cannot be run in DOS mode") 71 * is emitted as a separate byte blob after this header. */ 72 #define COFF_DOS_HEADER_SIZE 64u 73 #define IMAGE_DOS_SIGNATURE 0x5A4Du /* 'MZ' little-endian */ 74 #define IMAGE_NT_SIGNATURE 0x00004550u /* "PE\0\0" little-endian */ 75 76 typedef struct ImageDosHeader { 77 u16 e_magic; /* IMAGE_DOS_SIGNATURE */ 78 u16 e_cblp; 79 u16 e_cp; 80 u16 e_crlc; 81 u16 e_cparhdr; 82 u16 e_minalloc; 83 u16 e_maxalloc; 84 u16 e_ss; 85 u16 e_sp; 86 u16 e_csum; 87 u16 e_ip; 88 u16 e_cs; 89 u16 e_lfarlc; 90 u16 e_ovno; 91 u16 e_res[4]; 92 u16 e_oemid; 93 u16 e_oeminfo; 94 u16 e_res2[10]; 95 u32 e_lfanew; /* file offset of "PE\0\0" */ 96 } ImageDosHeader; 97 98 /* ---- optional header (PE32+, IMAGE_OPTIONAL_HEADER64) ---- 99 * On-disk size for PE32+ with 16 DataDirectory entries = 240 bytes: 100 * 28 (standard) + 88 (windows-specific) + 16*8 (data directories). */ 101 #define COFF_OPT_HDR64_SIZE 240u 102 #define COFF_DATA_DIRECTORY_SIZE 8u 103 #define COFF_NUM_DATA_DIRECTORIES 16u 104 105 #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020Bu 106 107 /* Subsystem (Subsystem field). */ 108 #define IMAGE_SUBSYSTEM_UNKNOWN 0u 109 #define IMAGE_SUBSYSTEM_NATIVE 1u 110 #define IMAGE_SUBSYSTEM_WINDOWS_GUI 2u 111 #define IMAGE_SUBSYSTEM_WINDOWS_CUI 3u /* console */ 112 113 /* DllCharacteristics. */ 114 #define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020u 115 #define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040u 116 #define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100u 117 #define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400u 118 #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000u 119 120 /* DataDirectory indices into ImageOptionalHeader64.DataDirectory[]. */ 121 #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 122 #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 123 #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 124 #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 125 #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 126 #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 127 #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 128 #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 129 #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 130 #define IMAGE_DIRECTORY_ENTRY_TLS 9 131 #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 132 #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 133 #define IMAGE_DIRECTORY_ENTRY_IAT 12 134 #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 135 #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 136 /* index 15 is reserved (must be zero) */ 137 138 typedef struct ImageDataDirectory { 139 u32 VirtualAddress; /* RVA */ 140 u32 Size; 141 } ImageDataDirectory; 142 143 typedef struct ImageOptionalHeader64 { 144 /* Standard fields (28 bytes for PE32+). */ 145 u16 Magic; /* IMAGE_NT_OPTIONAL_HDR64_MAGIC */ 146 u8 MajorLinkerVersion; 147 u8 MinorLinkerVersion; 148 u32 SizeOfCode; 149 u32 SizeOfInitializedData; 150 u32 SizeOfUninitializedData; 151 u32 AddressOfEntryPoint; /* RVA of _start */ 152 u32 BaseOfCode; 153 /* Windows-specific (88 bytes for PE32+). */ 154 u64 ImageBase; /* preferred load address */ 155 u32 SectionAlignment; /* in-memory alignment, >= page */ 156 u32 FileAlignment; /* on-disk alignment */ 157 u16 MajorOperatingSystemVersion; 158 u16 MinorOperatingSystemVersion; 159 u16 MajorImageVersion; 160 u16 MinorImageVersion; 161 u16 MajorSubsystemVersion; 162 u16 MinorSubsystemVersion; 163 u32 Win32VersionValue; /* reserved, zero */ 164 u32 SizeOfImage; /* in-memory size, SectionAlignment-padded */ 165 u32 SizeOfHeaders; /* file offset of first section's raw data */ 166 u32 CheckSum; 167 u16 Subsystem; /* IMAGE_SUBSYSTEM_* */ 168 u16 DllCharacteristics; /* IMAGE_DLLCHARACTERISTICS_* */ 169 u64 SizeOfStackReserve; 170 u64 SizeOfStackCommit; 171 u64 SizeOfHeapReserve; 172 u64 SizeOfHeapCommit; 173 u32 LoaderFlags; /* reserved, zero */ 174 u32 NumberOfRvaAndSizes; /* COFF_NUM_DATA_DIRECTORIES */ 175 /* Data directories (128 bytes = 16 * 8). */ 176 ImageDataDirectory DataDirectory[COFF_NUM_DATA_DIRECTORIES]; 177 } ImageOptionalHeader64; 178 179 /* ---- section header (IMAGE_SECTION_HEADER) ---- 180 * On-disk: 40 bytes, no padding. */ 181 #define COFF_SECTION_HEADER_SIZE 40u 182 183 /* Name field convention: 8 raw bytes. If the section name is <= 8 chars 184 * the bytes are the name, zero-padded (not necessarily NUL-terminated 185 * if exactly 8). For longer names (only legal in object files, not 186 * images) the form is "/<decimal-offset>" where <offset> is the 187 * little-endian decimal offset into the string table. Emit/read paths 188 * must marshal this convention explicitly. */ 189 typedef struct ImageSectionHeader { 190 char Name[8]; 191 u32 VirtualSize; /* size in image; for .obj usually 0 */ 192 u32 VirtualAddress; /* RVA in image; for .obj usually 0 */ 193 u32 SizeOfRawData; 194 u32 PointerToRawData; /* file offset */ 195 u32 PointerToRelocations; /* file offset of reloc array */ 196 u32 PointerToLinenumbers; /* file offset of COFF linenumbers (legacy) */ 197 u16 NumberOfRelocations; 198 u16 NumberOfLinenumbers; 199 u32 Characteristics; /* IMAGE_SCN_* */ 200 } ImageSectionHeader; 201 202 /* Section characteristics flags. */ 203 #define IMAGE_SCN_CNT_CODE 0x00000020u 204 #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040u 205 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080u 206 #define IMAGE_SCN_LNK_INFO 0x00000200u 207 #define IMAGE_SCN_LNK_REMOVE 0x00000800u 208 #define IMAGE_SCN_LNK_COMDAT 0x00001000u 209 #define IMAGE_SCN_GPREL 0x00008000u 210 #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000u 211 #define IMAGE_SCN_MEM_SHARED 0x10000000u 212 #define IMAGE_SCN_MEM_EXECUTE 0x20000000u 213 #define IMAGE_SCN_MEM_READ 0x40000000u 214 #define IMAGE_SCN_MEM_WRITE 0x80000000u 215 216 /* Alignment lives in bits 20..23 of Characteristics. Encoding is 217 * (log2(align) + 1) << 20: ALIGN_1BYTES = 1<<20, ALIGN_2BYTES = 2<<20, 218 * ..., ALIGN_8192BYTES = 14<<20. Zero in the field means "default" 219 * (16-byte for code). */ 220 #define IMAGE_SCN_ALIGN_1BYTES 0x00100000u 221 #define IMAGE_SCN_ALIGN_2BYTES 0x00200000u 222 #define IMAGE_SCN_ALIGN_4BYTES 0x00300000u 223 #define IMAGE_SCN_ALIGN_8BYTES 0x00400000u 224 #define IMAGE_SCN_ALIGN_16BYTES 0x00500000u 225 #define IMAGE_SCN_ALIGN_32BYTES 0x00600000u 226 #define IMAGE_SCN_ALIGN_64BYTES 0x00700000u 227 #define IMAGE_SCN_ALIGN_128BYTES 0x00800000u 228 #define IMAGE_SCN_ALIGN_256BYTES 0x00900000u 229 #define IMAGE_SCN_ALIGN_512BYTES 0x00A00000u 230 #define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000u 231 #define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000u 232 #define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000u 233 #define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000u 234 #define IMAGE_SCN_ALIGN_MASK 0x00F00000u 235 236 /* Encode an alignment given as log2(bytes): align=1 (2^0=1B) -> 1<<20, 237 * align=13 (2^13=8192B) -> 14<<20. */ 238 #define IMAGE_SCN_ALIGN_FROM_LOG2(n) (((u32)((n) + 1u)) << 20) 239 240 /* ---- symbol record (IMAGE_SYMBOL) ---- 241 * On-disk: 18 bytes per record, packed to 2-byte alignment (pragma 242 * pack(2) in the official headers). The host C struct below would 243 * have sizeof >= 20 due to padding; emit/read MUST marshal field by 244 * field — never write sizeof(ImageSymbol). The COFF_SYMBOL_SIZE 245 * constant is the source of truth. */ 246 #define COFF_SYMBOL_SIZE 18u 247 248 typedef struct ImageSymbol { 249 union { 250 char ShortName[8]; /* in-place if name <= 8 bytes */ 251 struct { 252 u32 Zeroes; /* 0 signals strtab lookup */ 253 u32 Offset; /* string-table offset (>= 4) */ 254 } LongName; 255 } Name; 256 u32 Value; 257 i16 SectionNumber; /* 1-based; specials below */ 258 u16 Type; /* low4=base, high12=derived */ 259 u8 StorageClass; /* IMAGE_SYM_CLASS_* */ 260 u8 NumberOfAuxSymbols; 261 } ImageSymbol; 262 263 /* Section number specials (i16-valued sentinel values). */ 264 #define IMAGE_SYM_UNDEFINED 0 265 #define IMAGE_SYM_ABSOLUTE (-1) 266 #define IMAGE_SYM_DEBUG (-2) 267 268 /* Type encoding. Low 4 bits = base type, high 12 bits = derived. The 269 * only derived-type bit kit distinguishes is FUNCTION (so a global 270 * is marked as a function when (Type >> 8) == DTYPE_FUNCTION). */ 271 #define IMAGE_SYM_TYPE_NULL 0u 272 #define IMAGE_SYM_DTYPE_NULL 0u 273 #define IMAGE_SYM_DTYPE_FUNCTION 2u 274 #define COFF_SYM_TYPE_FUNCTION (IMAGE_SYM_DTYPE_FUNCTION << 8) 275 276 /* Storage classes. The subset kit emits is EXTERNAL, STATIC, FILE, 277 * SECTION, WEAK_EXTERNAL; readers must additionally skip LABEL and 278 * FUNCTION (.bf/.ef debug pairs). END_OF_FUNCTION is signed -1 (the 279 * field is u8 so the wire value is 0xFF). */ 280 #define IMAGE_SYM_CLASS_END_OF_FUNCTION 0xFFu 281 #define IMAGE_SYM_CLASS_NULL 0u 282 #define IMAGE_SYM_CLASS_AUTOMATIC 1u 283 #define IMAGE_SYM_CLASS_EXTERNAL 2u 284 #define IMAGE_SYM_CLASS_STATIC 3u 285 #define IMAGE_SYM_CLASS_REGISTER 4u 286 #define IMAGE_SYM_CLASS_EXTERNAL_DEF 5u 287 #define IMAGE_SYM_CLASS_LABEL 6u 288 #define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7u 289 #define IMAGE_SYM_CLASS_FUNCTION 101u /* .bf / .ef markers */ 290 #define IMAGE_SYM_CLASS_FILE 103u /* aux records hold filename */ 291 #define IMAGE_SYM_CLASS_SECTION 104u 292 #define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105u 293 #define IMAGE_SYM_CLASS_CLR_TOKEN 107u 294 295 /* ---- aux records ---- 296 * Each aux record is exactly COFF_SYMBOL_SIZE (18 bytes) on disk; the 297 * structs below are wire-shaped but again must be marshalled field by 298 * field rather than via sizeof. */ 299 #define COFF_AUX_SECTION_SIZE 18u 300 #define COFF_AUX_WEAKEXTERN_SIZE 18u 301 #define COFF_AUX_FILE_SIZE 18u 302 #define COFF_AUX_FUNCTION_SIZE 18u 303 304 /* Follows a STATIC symbol whose Value is 0 and SectionNumber is the 305 * section's 1-based index. Encodes per-section metadata + COMDAT 306 * grouping. */ 307 typedef struct ImageAuxSymbolSection { 308 u32 Length; /* section's SizeOfRawData */ 309 u16 NumberOfRelocations; 310 u16 NumberOfLinenumbers; 311 u32 CheckSum; /* COMDAT checksum, 0 otherwise */ 312 u16 Number; /* associated section idx for COMDAT */ 313 u8 Selection; /* IMAGE_COMDAT_SELECT_* */ 314 u8 Unused[3]; 315 } ImageAuxSymbolSection; 316 317 /* Follows a WEAK_EXTERNAL symbol. TagIndex is the symbol-table index 318 * of the fall-back symbol used when the weak ref is unresolved. */ 319 typedef struct ImageAuxSymbolWeakExternal { 320 u32 TagIndex; 321 u32 Characteristics; /* IMAGE_WEAK_EXTERN_SEARCH_* */ 322 u8 Unused[10]; 323 } ImageAuxSymbolWeakExternal; 324 325 /* Follows a FILE symbol. For source paths longer than 18 bytes the 326 * NumberOfAuxSymbols on the parent FILE record is >1 and the name 327 * spans multiple aux records concatenated. */ 328 typedef struct ImageAuxSymbolFile { 329 char FileName[18]; 330 } ImageAuxSymbolFile; 331 332 /* Follows a FUNCTION (.bf/.ef) symbol. kit does not emit these but 333 * the reader must skip them when walking the symbol table. */ 334 typedef struct ImageAuxSymbolFunction { 335 u32 TagIndex; 336 u32 TotalSize; 337 u32 PointerToLinenumber; 338 u32 PointerToNextFunction; 339 u8 Unused[2]; 340 } ImageAuxSymbolFunction; 341 342 /* COMDAT selection (ImageAuxSymbolSection.Selection). */ 343 #define IMAGE_COMDAT_SELECT_NODUPLICATES 1u 344 #define IMAGE_COMDAT_SELECT_ANY 2u 345 #define IMAGE_COMDAT_SELECT_SAME_SIZE 3u 346 #define IMAGE_COMDAT_SELECT_EXACT_MATCH 4u 347 #define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5u 348 #define IMAGE_COMDAT_SELECT_LARGEST 6u 349 #define IMAGE_COMDAT_SELECT_NEWEST 7u 350 351 /* Weak-external resolution policy. */ 352 #define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1u 353 #define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2u 354 #define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3u 355 356 /* ---- relocation entry (IMAGE_RELOCATION) ---- 357 * On-disk: 10 bytes per record, packed to 2-byte alignment. Same 358 * sizeof caveat as ImageSymbol — never write sizeof(ImageRelocation), 359 * use COFF_RELOC_SIZE. */ 360 #define COFF_RELOC_SIZE 10u 361 362 typedef struct ImageRelocation { 363 u32 VirtualAddress; /* offset within the section being patched */ 364 u32 SymbolTableIndex; 365 u16 Type; /* IMAGE_REL_<machine>_* */ 366 } ImageRelocation; 367 368 /* ---- string table layout ---- 369 * Immediately follows the symbol table on disk: 370 * [0..3] u32 total size in bytes, INCLUSIVE of these 4 bytes. 371 * [4..] concatenated NUL-terminated UTF-8 strings. 372 * Therefore the smallest legal offset for a name reference is 4, and 373 * Offset == 0 in the LongName form is reserved (means "no string"). 374 * Empty string tables write the size field as 4 (i.e. no payload). */ 375 #define COFF_STRTAB_SIZE_FIELD_BYTES 4u 376 377 /* ---- base relocation block (IMAGE_BASE_RELOCATION) ---- 378 * Used in the .reloc directory of PE images. Each block describes 379 * fixups for one 4 KiB page: VirtualAddress is the page base RVA, the 380 * payload is (SizeOfBlock - 8) bytes of u16 entries packed as 381 * (type:4, offset:12) where offset is relative to VirtualAddress. */ 382 typedef struct ImageBaseRelocation { 383 u32 VirtualAddress; 384 u32 SizeOfBlock; /* header (8) + entries; padded to u32 */ 385 } ImageBaseRelocation; 386 #define COFF_BASE_RELOCATION_SIZE 8u 387 388 #define IMAGE_REL_BASED_ABSOLUTE 0u /* skip entry, used for padding */ 389 #define IMAGE_REL_BASED_HIGH 1u 390 #define IMAGE_REL_BASED_LOW 2u 391 #define IMAGE_REL_BASED_HIGHLOW 3u 392 #define IMAGE_REL_BASED_HIGHADJ 4u 393 #define IMAGE_REL_BASED_ARM_MOV32 5u 394 #define IMAGE_REL_BASED_DIR64 10u /* the one used on x64 / arm64 */ 395 396 /* ---- export directory (IMAGE_EXPORT_DIRECTORY) ---- 397 * One record, pointed at by IMAGE_DIRECTORY_ENTRY_EXPORT in the 398 * optional header. AddressOfFunctions is the EAT (u32 RVAs); the ENT 399 * (u32 RVAs at AddressOfNames) is parallel to the ordinal table 400 * (u16 ordinals at AddressOfNameOrdinals) and indexes into the EAT. 401 * An EAT entry whose RVA falls inside the export directory's own 402 * [VA, VA+Size) range is a *forwarder*: the bytes at that RVA are a 403 * "OTHERMODULE.OtherName" NUL-terminated string and the OS loader 404 * follows the chain at load time. */ 405 #define COFF_EXPORT_DIR_SIZE 40u 406 407 typedef struct ImageExportDirectory { 408 u32 Characteristics; 409 u32 TimeDateStamp; 410 u16 MajorVersion; 411 u16 MinorVersion; 412 u32 Name; /* RVA of DLL name */ 413 u32 Base; /* first ordinal */ 414 u32 NumberOfFunctions; 415 u32 NumberOfNames; 416 u32 AddressOfFunctions; /* EAT: RVA[NumberOfFunctions] */ 417 u32 AddressOfNames; /* ENT: RVA[NumberOfNames] */ 418 u32 AddressOfNameOrdinals; /* parallel ordinals: u16[NumberOfNames] */ 419 } ImageExportDirectory; 420 421 /* ---- import directory (IMAGE_IMPORT_DESCRIPTOR) ---- 422 * Array of these, terminated by an all-zero entry, lives at the RVA 423 * named by IMAGE_DIRECTORY_ENTRY_IMPORT in the optional header. 424 * OriginalFirstThunk -> the import lookup table (read-only); FirstThunk 425 * -> the IAT (overwritten by the loader with resolved addresses). */ 426 #define COFF_IMPORT_DESCRIPTOR_SIZE 20u 427 428 typedef struct ImageImportDescriptor { 429 u32 OriginalFirstThunk; /* RVA -> IMAGE_THUNK_DATA64[] (ILT) */ 430 u32 TimeDateStamp; 431 u32 ForwarderChain; 432 u32 Name; /* RVA -> NUL-terminated DLL name */ 433 u32 FirstThunk; /* RVA -> IMAGE_THUNK_DATA64[] (IAT) */ 434 } ImageImportDescriptor; 435 436 /* Thunk entries are u64 on PE32+. If the high bit (IMAGE_ORDINAL_FLAG64) 437 * is set, the low 16 bits hold an ordinal. Otherwise the value is an 438 * RVA to an IMAGE_IMPORT_BY_NAME record. */ 439 #define IMAGE_ORDINAL_FLAG64 0x8000000000000000ull 440 #define COFF_THUNK_DATA64_SIZE 8u 441 442 typedef struct ImageImportByName { 443 u16 Hint; /* index hint into the DLL's export table */ 444 /* char Name[]; NUL-terminated, followed by optional pad to even. */ 445 } ImageImportByName; 446 447 /* ---- TLS directory (IMAGE_TLS_DIRECTORY64) ---- 448 * Pointed at by IMAGE_DIRECTORY_ENTRY_TLS in the optional header. The 449 * loader walks the callbacks array (NUL-terminated) before main runs. */ 450 #define COFF_TLS_DIRECTORY64_SIZE 40u 451 452 typedef struct ImageTlsDirectory64 { 453 u64 StartAddressOfRawData; 454 u64 EndAddressOfRawData; 455 u64 AddressOfIndex; /* VA of u32 _tls_index */ 456 u64 AddressOfCallBacks; /* VA of NULL-terminated callback array */ 457 u32 SizeOfZeroFill; 458 u32 Characteristics; /* alignment encoded as IMAGE_SCN_ALIGN_* */ 459 } ImageTlsDirectory64; 460 461 /* ---- short import record (Microsoft .lib member) ---- 462 * Inside an archive whose member-data starts with Sig1==0, Sig2==0xFFFF 463 * the rest of the member is this "short import" descriptor: a fixed 464 * 20-byte header followed by SizeOfData bytes containing two 465 * NUL-terminated strings — symbol name then DLL name. */ 466 #define COFF_IMPORT_OBJECT_HEADER_SIZE 20u 467 #define IMPORT_OBJECT_HDR_SIG1 0x0000u 468 #define IMPORT_OBJECT_HDR_SIG2 0xFFFFu 469 470 typedef struct ImportObjectHeader { 471 u16 Sig1; /* IMPORT_OBJECT_HDR_SIG1 (0) */ 472 u16 Sig2; /* IMPORT_OBJECT_HDR_SIG2 (0xFFFF) */ 473 u16 Version; 474 u16 Machine; /* IMAGE_FILE_MACHINE_* */ 475 u32 TimeDateStamp; 476 u32 SizeOfData; /* bytes after this header */ 477 u16 OrdinalOrHint; 478 /* Bitfield encoded as a single u16 on the wire: 479 * Type:2, NameType:3, Reserved:11 (low-to-high). */ 480 u16 TypeFlags; 481 } ImportObjectHeader; 482 483 #define IMPORT_OBJECT_CODE 0u 484 #define IMPORT_OBJECT_DATA 1u 485 #define IMPORT_OBJECT_CONST 2u 486 487 #define IMPORT_OBJECT_ORDINAL 0u 488 #define IMPORT_OBJECT_NAME 1u 489 #define IMPORT_OBJECT_NAME_NOPREFIX 2u 490 #define IMPORT_OBJECT_NAME_UNDECORATE 3u 491 /* NameType 4 (EXPORTAS): the actual DLL export name is stored as a third 492 * NUL-terminated string after the symbol and DLL names. Used by the UCRT 493 * import libs to alias a mingw-local symbol (e.g. __msvcrt_assert) onto the 494 * real UCRT export (_assert). */ 495 #define IMPORT_OBJECT_NAME_EXPORTAS 4u 496 497 /* ---- debug directory (IMAGE_DEBUG_DIRECTORY) ---- 498 * Pointed at by IMAGE_DIRECTORY_ENTRY_DEBUG. kit emits a single 499 * IMAGE_DEBUG_TYPE_REPRO entry to mark the image as deterministic. */ 500 #define COFF_DEBUG_DIRECTORY_SIZE 28u 501 502 typedef struct ImageDebugDirectory { 503 u32 Characteristics; /* reserved, zero */ 504 u32 TimeDateStamp; 505 u16 MajorVersion; 506 u16 MinorVersion; 507 u32 Type; /* IMAGE_DEBUG_TYPE_* */ 508 u32 SizeOfData; 509 u32 AddressOfRawData; /* RVA in image */ 510 u32 PointerToRawData; /* file offset */ 511 } ImageDebugDirectory; 512 513 #define IMAGE_DEBUG_TYPE_UNKNOWN 0u 514 #define IMAGE_DEBUG_TYPE_COFF 1u 515 #define IMAGE_DEBUG_TYPE_CODEVIEW 2u 516 #define IMAGE_DEBUG_TYPE_MISC 4u 517 #define IMAGE_DEBUG_TYPE_REPRO 16u /* deterministic-build marker */ 518 519 /* ---- AMD64 (x86_64) PE/COFF wire reloc types ---- 520 * The REL32_N variants encode the PC base N bytes after the relocation 521 * field (so REL32_1 maps to a -1 implicit addend in kit's S + A - P 522 * model). Plain REL32 is relative to the byte after the 4-byte field. */ 523 #define IMAGE_REL_AMD64_ABSOLUTE 0u 524 #define IMAGE_REL_AMD64_ADDR64 1u /* 64-bit VA */ 525 #define IMAGE_REL_AMD64_ADDR32 2u /* 32-bit VA */ 526 #define IMAGE_REL_AMD64_ADDR32NB 3u /* 32-bit RVA (image-relative) */ 527 #define IMAGE_REL_AMD64_REL32 4u /* 32-bit relative to next inst */ 528 #define IMAGE_REL_AMD64_REL32_1 5u 529 #define IMAGE_REL_AMD64_REL32_2 6u 530 #define IMAGE_REL_AMD64_REL32_3 7u 531 #define IMAGE_REL_AMD64_REL32_4 8u 532 #define IMAGE_REL_AMD64_REL32_5 9u 533 #define IMAGE_REL_AMD64_SECTION 10u /* 16-bit section index */ 534 #define IMAGE_REL_AMD64_SECREL 11u /* 32-bit section-relative */ 535 #define IMAGE_REL_AMD64_SECREL7 12u 536 #define IMAGE_REL_AMD64_TOKEN 13u 537 #define IMAGE_REL_AMD64_SREL32 14u 538 #define IMAGE_REL_AMD64_PAIR 15u 539 #define IMAGE_REL_AMD64_SSPAN32 16u 540 541 /* ---- ARM64 PE/COFF wire reloc types ---- */ 542 #define IMAGE_REL_ARM64_ABSOLUTE 0u 543 #define IMAGE_REL_ARM64_ADDR32 1u 544 #define IMAGE_REL_ARM64_ADDR32NB 2u 545 #define IMAGE_REL_ARM64_BRANCH26 3u 546 #define IMAGE_REL_ARM64_PAGEBASE_REL21 4u 547 #define IMAGE_REL_ARM64_REL21 5u 548 #define IMAGE_REL_ARM64_PAGEOFFSET_12A 6u 549 #define IMAGE_REL_ARM64_PAGEOFFSET_12L 7u 550 #define IMAGE_REL_ARM64_SECREL 8u 551 #define IMAGE_REL_ARM64_SECREL_LOW12A 9u 552 #define IMAGE_REL_ARM64_SECREL_HIGH12A 10u 553 #define IMAGE_REL_ARM64_SECREL_LOW12L 11u 554 #define IMAGE_REL_ARM64_TOKEN 12u 555 #define IMAGE_REL_ARM64_SECTION 13u 556 #define IMAGE_REL_ARM64_ADDR64 14u 557 #define IMAGE_REL_ARM64_BRANCH19 15u 558 #define IMAGE_REL_ARM64_BRANCH14 16u 559 #define IMAGE_REL_ARM64_REL32 17u 560 561 /* ---- per-arch reloc translators ---- 562 * Map kit-canonical RelocKind <-> PE/COFF wire type. Contract 563 * matches elf_<arch>_reloc_{to,from}: 564 * _to: returns the wire type, or IMAGE_REL_*_ABSOLUTE (== 0) for 565 * unsupported input. Callers treat that as a panic trigger. 566 * _from: returns the canonical RelocKind, or (u32)-1 on unknown 567 * input. Callers diagnose the unknown wire value. */ 568 u32 coff_x86_64_reloc_to(u32 kind /* RelocKind */); 569 u32 coff_x86_64_reloc_from(u32 wire_type); 570 u32 coff_aarch64_reloc_to(u32 kind /* RelocKind */); 571 u32 coff_aarch64_reloc_from(u32 wire_type); 572 573 /* ---- little-endian byte writers/readers (Writer-based) ---- 574 * Writes go through the shared writer_u*_le helpers (core/bytes.h); the 575 * coff_wr_* / coff_rd_* aliases keep the COFF spelling at call sites. */ 576 577 #define coff_wr_u8 writer_u8_le 578 #define coff_wr_u16 writer_u16_le 579 #define coff_wr_u32 writer_u32_le 580 #define coff_wr_u64 writer_u64_le 581 582 static inline u16 coff_rd_u16(const u8* p) { return rd_u16_le(p); } 583 static inline u32 coff_rd_u32(const u8* p) { return rd_u32_le(p); } 584 static inline u64 coff_rd_u64(const u8* p) { return rd_u64_le(p); } 585 586 #endif /* KIT_OBJ_COFF_H */