kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 */