master
   1const std = @import("std.zig");
   2const assert = std.debug.assert;
   3const mem = std.mem;
   4
   5pub const Header = extern struct {
   6    /// The number that identifies the type of target machine.
   7    machine: IMAGE.FILE.MACHINE,
   8
   9    /// The number of sections. This indicates the size of the section table, which immediately follows the headers.
  10    number_of_sections: u16,
  11
  12    /// The low 32 bits of the number of seconds since 00:00 January 1, 1970 (a C run-time time_t value),
  13    /// which indicates when the file was created.
  14    time_date_stamp: u32,
  15
  16    /// The file offset of the COFF symbol table, or zero if no COFF symbol table is present.
  17    /// This value should be zero for an image because COFF debugging information is deprecated.
  18    pointer_to_symbol_table: u32,
  19
  20    /// The number of entries in the symbol table.
  21    /// This data can be used to locate the string table, which immediately follows the symbol table.
  22    /// This value should be zero for an image because COFF debugging information is deprecated.
  23    number_of_symbols: u32,
  24
  25    /// The size of the optional header, which is required for executable files but not for object files.
  26    /// This value should be zero for an object file. For a description of the header format, see Optional Header (Image Only).
  27    size_of_optional_header: u16,
  28
  29    /// The flags that indicate the attributes of the file.
  30    flags: Header.Flags,
  31
  32    pub const Flags = packed struct(u16) {
  33        /// Image only, Windows CE, and Microsoft Windows NT and later.
  34        /// This indicates that the file does not contain base relocations
  35        /// and must therefore be loaded at its preferred base address.
  36        /// If the base address is not available, the loader reports an error.
  37        /// The default behavior of the linker is to strip base relocations
  38        /// from executable (EXE) files.
  39        RELOCS_STRIPPED: bool = false,
  40
  41        /// Image only. This indicates that the image file is valid and can be run.
  42        /// If this flag is not set, it indicates a linker error.
  43        EXECUTABLE_IMAGE: bool = false,
  44
  45        /// COFF line numbers have been removed. This flag is deprecated and should be zero.
  46        LINE_NUMS_STRIPPED: bool = false,
  47
  48        /// COFF symbol table entries for local symbols have been removed.
  49        /// This flag is deprecated and should be zero.
  50        LOCAL_SYMS_STRIPPED: bool = false,
  51
  52        /// Obsolete. Aggressively trim working set.
  53        /// This flag is deprecated for Windows 2000 and later and must be zero.
  54        AGGRESSIVE_WS_TRIM: bool = false,
  55
  56        /// Application can handle > 2-GB addresses.
  57        LARGE_ADDRESS_AWARE: bool = false,
  58
  59        /// This flag is reserved for future use.
  60        RESERVED: bool = false,
  61
  62        /// Little endian: the least significant bit (LSB) precedes the
  63        /// most significant bit (MSB) in memory. This flag is deprecated and should be zero.
  64        BYTES_REVERSED_LO: bool = false,
  65
  66        /// Machine is based on a 32-bit-word architecture.
  67        @"32BIT_MACHINE": bool = false,
  68
  69        /// Debugging information is removed from the image file.
  70        DEBUG_STRIPPED: bool = false,
  71
  72        /// If the image is on removable media, fully load it and copy it to the swap file.
  73        REMOVABLE_RUN_FROM_SWAP: bool = false,
  74
  75        /// If the image is on network media, fully load it and copy it to the swap file.
  76        NET_RUN_FROM_SWAP: bool = false,
  77
  78        /// The image file is a system file, not a user program.
  79        SYSTEM: bool = false,
  80
  81        /// The image file is a dynamic-link library (DLL).
  82        /// Such files are considered executable files for almost all purposes,
  83        /// although they cannot be directly run.
  84        DLL: bool = false,
  85
  86        /// The file should be run only on a uniprocessor machine.
  87        UP_SYSTEM_ONLY: bool = false,
  88
  89        /// Big endian: the MSB precedes the LSB in memory. This flag is deprecated and should be zero.
  90        BYTES_REVERSED_HI: bool = false,
  91    };
  92};
  93
  94// OptionalHeader.magic values
  95// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
  96pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC = @intFromEnum(OptionalHeader.Magic.PE32);
  97pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC = @intFromEnum(OptionalHeader.Magic.@"PE32+");
  98
  99pub const DllFlags = packed struct(u16) {
 100    _reserved_0: u5 = 0,
 101
 102    /// Image can handle a high entropy 64-bit virtual address space.
 103    HIGH_ENTROPY_VA: bool = false,
 104
 105    /// DLL can be relocated at load time.
 106    DYNAMIC_BASE: bool = false,
 107
 108    /// Code Integrity checks are enforced.
 109    FORCE_INTEGRITY: bool = false,
 110
 111    /// Image is NX compatible.
 112    NX_COMPAT: bool = false,
 113
 114    /// Isolation aware, but do not isolate the image.
 115    NO_ISOLATION: bool = false,
 116
 117    /// Does not use structured exception (SE) handling. No SE handler may be called in this image.
 118    NO_SEH: bool = false,
 119
 120    /// Do not bind the image.
 121    NO_BIND: bool = false,
 122
 123    /// Image must execute in an AppContainer.
 124    APPCONTAINER: bool = false,
 125
 126    /// A WDM driver.
 127    WDM_DRIVER: bool = false,
 128
 129    /// Image supports Control Flow Guard.
 130    GUARD_CF: bool = false,
 131
 132    /// Terminal Server aware.
 133    TERMINAL_SERVER_AWARE: bool = false,
 134};
 135
 136pub const Subsystem = enum(u16) {
 137    /// An unknown subsystem
 138    UNKNOWN = 0,
 139
 140    /// Device drivers and native Windows processes
 141    NATIVE = 1,
 142
 143    /// The Windows graphical user interface (GUI) subsystem
 144    WINDOWS_GUI = 2,
 145
 146    /// The Windows character subsystem
 147    WINDOWS_CUI = 3,
 148
 149    /// The OS/2 character subsystem
 150    OS2_CUI = 5,
 151
 152    /// The Posix character subsystem
 153    POSIX_CUI = 7,
 154
 155    /// Native Win9x driver
 156    NATIVE_WINDOWS = 8,
 157
 158    /// Windows CE
 159    WINDOWS_CE_GUI = 9,
 160
 161    /// An Extensible Firmware Interface (EFI) application
 162    EFI_APPLICATION = 10,
 163
 164    /// An EFI driver with boot services
 165    EFI_BOOT_SERVICE_DRIVER = 11,
 166
 167    /// An EFI driver with run-time services
 168    EFI_RUNTIME_DRIVER = 12,
 169
 170    /// An EFI ROM image
 171    EFI_ROM = 13,
 172
 173    /// XBOX
 174    XBOX = 14,
 175
 176    /// Windows boot application
 177    WINDOWS_BOOT_APPLICATION = 16,
 178
 179    _,
 180};
 181
 182pub const OptionalHeader = extern struct {
 183    magic: OptionalHeader.Magic,
 184    major_linker_version: u8,
 185    minor_linker_version: u8,
 186    size_of_code: u32,
 187    size_of_initialized_data: u32,
 188    size_of_uninitialized_data: u32,
 189    address_of_entry_point: u32,
 190    base_of_code: u32,
 191
 192    pub const Magic = enum(u16) {
 193        PE32 = 0x10b,
 194        @"PE32+" = 0x20b,
 195        _,
 196    };
 197
 198    pub const PE32 = extern struct {
 199        standard: OptionalHeader,
 200        base_of_data: u32,
 201        image_base: u32,
 202        section_alignment: u32,
 203        file_alignment: u32,
 204        major_operating_system_version: u16,
 205        minor_operating_system_version: u16,
 206        major_image_version: u16,
 207        minor_image_version: u16,
 208        major_subsystem_version: u16,
 209        minor_subsystem_version: u16,
 210        win32_version_value: u32,
 211        size_of_image: u32,
 212        size_of_headers: u32,
 213        checksum: u32,
 214        subsystem: Subsystem,
 215        dll_flags: DllFlags,
 216        size_of_stack_reserve: u32,
 217        size_of_stack_commit: u32,
 218        size_of_heap_reserve: u32,
 219        size_of_heap_commit: u32,
 220        loader_flags: u32,
 221        number_of_rva_and_sizes: u32,
 222    };
 223
 224    pub const @"PE32+" = extern struct {
 225        standard: OptionalHeader,
 226        image_base: u64,
 227        section_alignment: u32,
 228        file_alignment: u32,
 229        major_operating_system_version: u16,
 230        minor_operating_system_version: u16,
 231        major_image_version: u16,
 232        minor_image_version: u16,
 233        major_subsystem_version: u16,
 234        minor_subsystem_version: u16,
 235        win32_version_value: u32,
 236        size_of_image: u32,
 237        size_of_headers: u32,
 238        checksum: u32,
 239        subsystem: Subsystem,
 240        dll_flags: DllFlags,
 241        size_of_stack_reserve: u64,
 242        size_of_stack_commit: u64,
 243        size_of_heap_reserve: u64,
 244        size_of_heap_commit: u64,
 245        loader_flags: u32,
 246        number_of_rva_and_sizes: u32,
 247    };
 248};
 249
 250pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
 251
 252pub const ImageDataDirectory = extern struct {
 253    virtual_address: u32,
 254    size: u32,
 255};
 256
 257pub const BaseRelocationDirectoryEntry = extern struct {
 258    /// The image base plus the page RVA is added to each offset to create the VA where the base relocation must be applied.
 259    page_rva: u32,
 260
 261    /// The total number of bytes in the base relocation block, including the Page RVA and Block Size fields and the Type/Offset fields that follow.
 262    block_size: u32,
 263};
 264
 265pub const BaseRelocation = packed struct(u16) {
 266    /// Stored in the remaining 12 bits of the WORD, an offset from the starting address that was specified in the Page RVA field for the block.
 267    /// This offset specifies where the base relocation is to be applied.
 268    offset: u12,
 269
 270    /// Stored in the high 4 bits of the WORD, a value that indicates the type of base relocation to be applied.
 271    type: BaseRelocationType,
 272};
 273
 274pub const BaseRelocationType = enum(u4) {
 275    /// The base relocation is skipped. This type can be used to pad a block.
 276    ABSOLUTE = 0,
 277
 278    /// The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word.
 279    HIGH = 1,
 280
 281    /// The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the low half of a 32-bit word.
 282    LOW = 2,
 283
 284    /// The base relocation applies all 32 bits of the difference to the 32-bit field at offset.
 285    HIGHLOW = 3,
 286
 287    /// The base relocation adds the high 16 bits of the difference to the 16-bit field at offset.
 288    /// The 16-bit field represents the high value of a 32-bit word.
 289    /// The low 16 bits of the 32-bit value are stored in the 16-bit word that follows this base relocation.
 290    /// This means that this base relocation occupies two slots.
 291    HIGHADJ = 4,
 292
 293    /// When the machine type is MIPS, the base relocation applies to a MIPS jump instruction.
 294    MIPS_JMPADDR = 5,
 295
 296    /// This relocation is meaningful only when the machine type is ARM or Thumb.
 297    /// The base relocation applies the 32-bit address of a symbol across a consecutive MOVW/MOVT instruction pair.
 298    // ARM_MOV32 = 5,
 299
 300    /// This relocation is only meaningful when the machine type is RISC-V.
 301    /// The base relocation applies to the high 20 bits of a 32-bit absolute address.
 302    // RISCV_HIGH20 = 5,
 303
 304    /// Reserved, must be zero.
 305    RESERVED = 6,
 306
 307    /// This relocation is meaningful only when the machine type is Thumb.
 308    /// The base relocation applies the 32-bit address of a symbol to a consecutive MOVW/MOVT instruction pair.
 309    THUMB_MOV32 = 7,
 310
 311    /// This relocation is only meaningful when the machine type is RISC-V.
 312    /// The base relocation applies to the low 12 bits of a 32-bit absolute address formed in RISC-V I-type instruction format.
 313    // RISCV_LOW12I = 7,
 314
 315    /// This relocation is only meaningful when the machine type is RISC-V.
 316    /// The base relocation applies to the low 12 bits of a 32-bit absolute address formed in RISC-V S-type instruction format.
 317    RISCV_LOW12S = 8,
 318
 319    /// This relocation is only meaningful when the machine type is LoongArch 32-bit.
 320    /// The base relocation applies to a 32-bit absolute address formed in two consecutive instructions.
 321    // LOONGARCH32_MARK_LA = 8,
 322
 323    /// This relocation is only meaningful when the machine type is LoongArch 64-bit.
 324    /// The base relocation applies to a 64-bit absolute address formed in four consecutive instructions.
 325    // LOONGARCH64_MARK_LA = 8,
 326
 327    /// The relocation is only meaningful when the machine type is MIPS.
 328    /// The base relocation applies to a MIPS16 jump instruction.
 329    MIPS_JMPADDR16 = 9,
 330
 331    /// The base relocation applies the difference to the 64-bit field at offset.
 332    DIR64 = 10,
 333
 334    _,
 335};
 336
 337pub const DebugDirectoryEntry = extern struct {
 338    characteristics: u32,
 339    time_date_stamp: u32,
 340    major_version: u16,
 341    minor_version: u16,
 342    type: DebugType,
 343    size_of_data: u32,
 344    address_of_raw_data: u32,
 345    pointer_to_raw_data: u32,
 346};
 347
 348pub const DebugType = enum(u32) {
 349    UNKNOWN = 0,
 350    COFF = 1,
 351    CODEVIEW = 2,
 352    FPO = 3,
 353    MISC = 4,
 354    EXCEPTION = 5,
 355    FIXUP = 6,
 356    OMAP_TO_SRC = 7,
 357    OMAP_FROM_SRC = 8,
 358    BORLAND = 9,
 359    RESERVED10 = 10,
 360    VC_FEATURE = 12,
 361    POGO = 13,
 362    ILTCG = 14,
 363    MPX = 15,
 364    REPRO = 16,
 365    EX_DLLCHARACTERISTICS = 20,
 366
 367    _,
 368};
 369
 370pub const ImportDirectoryEntry = extern struct {
 371    /// The RVA of the import lookup table.
 372    /// This table contains a name or ordinal for each import.
 373    /// (The name "Characteristics" is used in Winnt.h, but no longer describes this field.)
 374    import_lookup_table_rva: u32,
 375
 376    /// The stamp that is set to zero until the image is bound.
 377    /// After the image is bound, this field is set to the time/data stamp of the DLL.
 378    time_date_stamp: u32,
 379
 380    /// The index of the first forwarder reference.
 381    forwarder_chain: u32,
 382
 383    /// The address of an ASCII string that contains the name of the DLL.
 384    /// This address is relative to the image base.
 385    name_rva: u32,
 386
 387    /// The RVA of the import address table.
 388    /// The contents of this table are identical to the contents of the import lookup table until the image is bound.
 389    import_address_table_rva: u32,
 390};
 391
 392pub const ImportLookupEntry32 = struct {
 393    pub const ByName = packed struct(u32) {
 394        name_table_rva: u31,
 395        flag: u1 = 0,
 396    };
 397
 398    pub const ByOrdinal = packed struct(u32) {
 399        ordinal_number: u16,
 400        unused: u15 = 0,
 401        flag: u1 = 1,
 402    };
 403
 404    const mask = 0x80000000;
 405
 406    pub fn getImportByName(raw: u32) ?ByName {
 407        if (mask & raw != 0) return null;
 408        return @as(ByName, @bitCast(raw));
 409    }
 410
 411    pub fn getImportByOrdinal(raw: u32) ?ByOrdinal {
 412        if (mask & raw == 0) return null;
 413        return @as(ByOrdinal, @bitCast(raw));
 414    }
 415};
 416
 417pub const ImportLookupEntry64 = struct {
 418    pub const ByName = packed struct(u64) {
 419        name_table_rva: u31,
 420        unused: u32 = 0,
 421        flag: u1 = 0,
 422    };
 423
 424    pub const ByOrdinal = packed struct(u64) {
 425        ordinal_number: u16,
 426        unused: u47 = 0,
 427        flag: u1 = 1,
 428    };
 429
 430    const mask = 0x8000000000000000;
 431
 432    pub fn getImportByName(raw: u64) ?ByName {
 433        if (mask & raw != 0) return null;
 434        return @as(ByName, @bitCast(raw));
 435    }
 436
 437    pub fn getImportByOrdinal(raw: u64) ?ByOrdinal {
 438        if (mask & raw == 0) return null;
 439        return @as(ByOrdinal, @bitCast(raw));
 440    }
 441};
 442
 443/// Every name ends with a NULL byte. IF the NULL byte does not fall on
 444/// 2byte boundary, the entry structure is padded to ensure 2byte alignment.
 445pub const ImportHintNameEntry = extern struct {
 446    /// An index into the export name pointer table.
 447    /// A match is attempted first with this value. If it fails, a binary search is performed on the DLL's export name pointer table.
 448    hint: u16,
 449
 450    /// Pointer to NULL terminated ASCII name.
 451    /// Variable length...
 452    name: [1]u8,
 453};
 454
 455pub const SectionHeader = extern struct {
 456    name: [8]u8,
 457    virtual_size: u32,
 458    virtual_address: u32,
 459    size_of_raw_data: u32,
 460    pointer_to_raw_data: u32,
 461    pointer_to_relocations: u32,
 462    pointer_to_linenumbers: u32,
 463    number_of_relocations: u16,
 464    number_of_linenumbers: u16,
 465    flags: SectionHeader.Flags,
 466
 467    pub fn getName(self: *align(1) const SectionHeader) ?[]const u8 {
 468        if (self.name[0] == '/') return null;
 469        const len = std.mem.indexOfScalar(u8, &self.name, @as(u8, 0)) orelse self.name.len;
 470        return self.name[0..len];
 471    }
 472
 473    pub fn getNameOffset(self: SectionHeader) ?u32 {
 474        if (self.name[0] != '/') return null;
 475        const len = std.mem.indexOfScalar(u8, &self.name, @as(u8, 0)) orelse self.name.len;
 476        const offset = std.fmt.parseInt(u32, self.name[1..len], 10) catch unreachable;
 477        return offset;
 478    }
 479
 480    /// Applicable only to section headers in COFF objects.
 481    pub fn getAlignment(self: SectionHeader) ?u16 {
 482        return self.flags.ALIGN.toByteUnits();
 483    }
 484
 485    pub fn setAlignment(self: *SectionHeader, new_alignment: u16) void {
 486        self.flags.ALIGN = .fromByteUnits(new_alignment);
 487    }
 488
 489    pub fn isCode(self: SectionHeader) bool {
 490        return self.flags.CNT_CODE;
 491    }
 492
 493    pub fn isComdat(self: SectionHeader) bool {
 494        return self.flags.LNK_COMDAT;
 495    }
 496
 497    pub const Flags = packed struct(u32) {
 498        SCALE_INDEX: bool = false,
 499
 500        unused1: u2 = 0,
 501
 502        /// The section should not be padded to the next boundary.
 503        /// This flag is obsolete and is replaced by `.ALIGN = .@"1BYTES"`.
 504        /// This is valid only for object files.
 505        TYPE_NO_PAD: bool = false,
 506
 507        unused4: u1 = 0,
 508
 509        /// The section contains executable code.
 510        CNT_CODE: bool = false,
 511
 512        /// The section contains initialized data.
 513        CNT_INITIALIZED_DATA: bool = false,
 514
 515        /// The section contains uninitialized data.
 516        CNT_UNINITIALIZED_DATA: bool = false,
 517
 518        /// Reserved for future use.
 519        LNK_OTHER: bool = false,
 520
 521        /// The section contains comments or other information.
 522        /// The .drectve section has this type.
 523        /// This is valid for object files only.
 524        LNK_INFO: bool = false,
 525
 526        unused10: u1 = 0,
 527
 528        /// The section will not become part of the image.
 529        /// This is valid only for object files.
 530        LNK_REMOVE: bool = false,
 531
 532        /// The section contains COMDAT data.
 533        /// For more information, see COMDAT Sections (Object Only).
 534        /// This is valid only for object files.
 535        LNK_COMDAT: bool = false,
 536
 537        unused13: u2 = 0,
 538
 539        union14: packed union {
 540            mask: u1,
 541            /// The section contains data referenced through the global pointer (GP).
 542            GPREL: bool,
 543            MEM_FARDATA: bool,
 544        } = .{ .mask = 0 },
 545
 546        unused15: u1 = 0,
 547
 548        union16: packed union {
 549            mask: u1,
 550            MEM_PURGEABLE: bool,
 551            MEM_16BIT: bool,
 552        } = .{ .mask = 0 },
 553
 554        /// Reserved for future use.
 555        MEM_LOCKED: bool = false,
 556
 557        /// Reserved for future use.
 558        MEM_PRELOAD: bool = false,
 559
 560        ALIGN: SectionHeader.Flags.Align = .NONE,
 561
 562        /// The section contains extended relocations.
 563        LNK_NRELOC_OVFL: bool = false,
 564
 565        /// The section can be discarded as needed.
 566        MEM_DISCARDABLE: bool = false,
 567
 568        /// The section cannot be cached.
 569        MEM_NOT_CACHED: bool = false,
 570
 571        /// The section is not pageable.
 572        MEM_NOT_PAGED: bool = false,
 573
 574        /// The section can be shared in memory.
 575        MEM_SHARED: bool = false,
 576
 577        /// The section can be executed as code.
 578        MEM_EXECUTE: bool = false,
 579
 580        /// The section can be read.
 581        MEM_READ: bool = false,
 582
 583        /// The section can be written to.
 584        MEM_WRITE: bool = false,
 585
 586        pub const Align = enum(u4) {
 587            NONE = 0,
 588            @"1BYTES" = 1,
 589            @"2BYTES" = 2,
 590            @"4BYTES" = 3,
 591            @"8BYTES" = 4,
 592            @"16BYTES" = 5,
 593            @"32BYTES" = 6,
 594            @"64BYTES" = 7,
 595            @"128BYTES" = 8,
 596            @"256BYTES" = 9,
 597            @"512BYTES" = 10,
 598            @"1024BYTES" = 11,
 599            @"2048BYTES" = 12,
 600            @"4096BYTES" = 13,
 601            @"8192BYTES" = 14,
 602            _,
 603
 604            pub fn toByteUnits(a: Align) ?u16 {
 605                if (a == .NONE) return null;
 606                return @as(u16, 1) << (@intFromEnum(a) - 1);
 607            }
 608
 609            pub fn fromByteUnits(n: u16) Align {
 610                std.debug.assert(std.math.isPowerOfTwo(n));
 611                return @enumFromInt(@ctz(n) + 1);
 612            }
 613        };
 614    };
 615};
 616
 617pub const Symbol = struct {
 618    name: [8]u8,
 619    value: u32,
 620    section_number: SectionNumber,
 621    type: SymType,
 622    storage_class: StorageClass,
 623    number_of_aux_symbols: u8,
 624
 625    pub fn sizeOf() usize {
 626        return 18;
 627    }
 628
 629    pub fn getName(self: *const Symbol) ?[]const u8 {
 630        if (std.mem.eql(u8, self.name[0..4], "\x00\x00\x00\x00")) return null;
 631        const len = std.mem.indexOfScalar(u8, &self.name, @as(u8, 0)) orelse self.name.len;
 632        return self.name[0..len];
 633    }
 634
 635    pub fn getNameOffset(self: Symbol) ?u32 {
 636        if (!std.mem.eql(u8, self.name[0..4], "\x00\x00\x00\x00")) return null;
 637        const offset = std.mem.readInt(u32, self.name[4..8], .little);
 638        return offset;
 639    }
 640};
 641
 642pub const SectionNumber = enum(u16) {
 643    /// The symbol record is not yet assigned a section.
 644    /// A value of zero indicates that a reference to an external symbol is defined elsewhere.
 645    /// A value of non-zero is a common symbol with a size that is specified by the value.
 646    UNDEFINED = 0,
 647
 648    /// The symbol has an absolute (non-relocatable) value and is not an address.
 649    ABSOLUTE = 0xffff,
 650
 651    /// The symbol provides general type or debugging information but does not correspond to a section.
 652    /// Microsoft tools use this setting along with .file records (storage class FILE).
 653    DEBUG = 0xfffe,
 654    _,
 655};
 656
 657pub const SymType = packed struct(u16) {
 658    complex_type: ComplexType,
 659    base_type: BaseType,
 660};
 661
 662pub const BaseType = enum(u8) {
 663    /// No type information or unknown base type. Microsoft tools use this setting
 664    NULL = 0,
 665
 666    /// No valid type; used with void pointers and functions
 667    VOID = 1,
 668
 669    /// A character (signed byte)
 670    CHAR = 2,
 671
 672    /// A 2-byte signed integer
 673    SHORT = 3,
 674
 675    /// A natural integer type (normally 4 bytes in Windows)
 676    INT = 4,
 677
 678    /// A 4-byte signed integer
 679    LONG = 5,
 680
 681    /// A 4-byte floating-point number
 682    FLOAT = 6,
 683
 684    /// An 8-byte floating-point number
 685    DOUBLE = 7,
 686
 687    /// A structure
 688    STRUCT = 8,
 689
 690    /// A union
 691    UNION = 9,
 692
 693    /// An enumerated type
 694    ENUM = 10,
 695
 696    /// A member of enumeration (a specified value)
 697    MOE = 11,
 698
 699    /// A byte; unsigned 1-byte integer
 700    BYTE = 12,
 701
 702    /// A word; unsigned 2-byte integer
 703    WORD = 13,
 704
 705    /// An unsigned integer of natural size (normally, 4 bytes)
 706    UINT = 14,
 707
 708    /// An unsigned 4-byte integer
 709    DWORD = 15,
 710
 711    _,
 712};
 713
 714pub const ComplexType = enum(u8) {
 715    /// No derived type; the symbol is a simple scalar variable.
 716    NULL = 0,
 717
 718    /// The symbol is a pointer to base type.
 719    POINTER = 16,
 720
 721    /// The symbol is a function that returns a base type.
 722    FUNCTION = 32,
 723
 724    /// The symbol is an array of base type.
 725    ARRAY = 48,
 726
 727    _,
 728};
 729
 730pub const StorageClass = enum(u8) {
 731    /// A special symbol that represents the end of function, for debugging purposes.
 732    END_OF_FUNCTION = 0xff,
 733
 734    /// No assigned storage class.
 735    NULL = 0,
 736
 737    /// The automatic (stack) variable. The Value field specifies the stack frame offset.
 738    AUTOMATIC = 1,
 739
 740    /// A value that Microsoft tools use for external symbols.
 741    /// The Value field indicates the size if the section number is IMAGE_SYM_UNDEFINED (0).
 742    /// If the section number is not zero, then the Value field specifies the offset within the section.
 743    EXTERNAL = 2,
 744
 745    /// The offset of the symbol within the section.
 746    /// If the Value field is zero, then the symbol represents a section name.
 747    STATIC = 3,
 748
 749    /// A register variable.
 750    /// The Value field specifies the register number.
 751    REGISTER = 4,
 752
 753    /// A symbol that is defined externally.
 754    EXTERNAL_DEF = 5,
 755
 756    /// A code label that is defined within the module.
 757    /// The Value field specifies the offset of the symbol within the section.
 758    LABEL = 6,
 759
 760    /// A reference to a code label that is not defined.
 761    UNDEFINED_LABEL = 7,
 762
 763    /// The structure member. The Value field specifies the n th member.
 764    MEMBER_OF_STRUCT = 8,
 765
 766    /// A formal argument (parameter) of a function. The Value field specifies the n th argument.
 767    ARGUMENT = 9,
 768
 769    /// The structure tag-name entry.
 770    STRUCT_TAG = 10,
 771
 772    /// A union member. The Value field specifies the n th member.
 773    MEMBER_OF_UNION = 11,
 774
 775    /// The Union tag-name entry.
 776    UNION_TAG = 12,
 777
 778    /// A Typedef entry.
 779    TYPE_DEFINITION = 13,
 780
 781    /// A static data declaration.
 782    UNDEFINED_STATIC = 14,
 783
 784    /// An enumerated type tagname entry.
 785    ENUM_TAG = 15,
 786
 787    /// A member of an enumeration. The Value field specifies the n th member.
 788    MEMBER_OF_ENUM = 16,
 789
 790    /// A register parameter.
 791    REGISTER_PARAM = 17,
 792
 793    /// A bit-field reference. The Value field specifies the n th bit in the bit field.
 794    BIT_FIELD = 18,
 795
 796    /// A .bb (beginning of block) or .eb (end of block) record.
 797    /// The Value field is the relocatable address of the code location.
 798    BLOCK = 100,
 799
 800    /// A value that Microsoft tools use for symbol records that define the extent of a function: begin function (.bf ), end function ( .ef ), and lines in function ( .lf ).
 801    /// For .lf records, the Value field gives the number of source lines in the function.
 802    /// For .ef records, the Value field gives the size of the function code.
 803    FUNCTION = 101,
 804
 805    /// An end-of-structure entry.
 806    END_OF_STRUCT = 102,
 807
 808    /// A value that Microsoft tools, as well as traditional COFF format, use for the source-file symbol record.
 809    /// The symbol is followed by auxiliary records that name the file.
 810    FILE = 103,
 811
 812    /// A definition of a section (Microsoft tools use STATIC storage class instead).
 813    SECTION = 104,
 814
 815    /// A weak external. For more information, see Auxiliary Format 3: Weak Externals.
 816    WEAK_EXTERNAL = 105,
 817
 818    /// A CLR token symbol. The name is an ASCII string that consists of the hexadecimal value of the token.
 819    /// For more information, see CLR Token Definition (Object Only).
 820    CLR_TOKEN = 107,
 821
 822    _,
 823};
 824
 825pub const FunctionDefinition = struct {
 826    /// The symbol-table index of the corresponding .bf (begin function) symbol record.
 827    tag_index: u32,
 828
 829    /// The size of the executable code for the function itself.
 830    /// If the function is in its own section, the SizeOfRawData in the section header is greater or equal to this field,
 831    /// depending on alignment considerations.
 832    total_size: u32,
 833
 834    /// The file offset of the first COFF line-number entry for the function, or zero if none exists.
 835    pointer_to_linenumber: u32,
 836
 837    /// The symbol-table index of the record for the next function.
 838    /// If the function is the last in the symbol table, this field is set to zero.
 839    pointer_to_next_function: u32,
 840
 841    unused: [2]u8,
 842};
 843
 844pub const SectionDefinition = struct {
 845    /// The size of section data; the same as SizeOfRawData in the section header.
 846    length: u32,
 847
 848    /// The number of relocation entries for the section.
 849    number_of_relocations: u16,
 850
 851    /// The number of line-number entries for the section.
 852    number_of_linenumbers: u16,
 853
 854    /// The checksum for communal data. It is applicable if the IMAGE_SCN_LNK_COMDAT flag is set in the section header.
 855    checksum: u32,
 856
 857    /// One-based index into the section table for the associated section. This is used when the COMDAT selection setting is 5.
 858    number: u16,
 859
 860    /// The COMDAT selection number. This is applicable if the section is a COMDAT section.
 861    selection: ComdatSelection,
 862
 863    unused: [3]u8,
 864};
 865
 866pub const FileDefinition = struct {
 867    /// An ANSI string that gives the name of the source file.
 868    /// This is padded with nulls if it is less than the maximum length.
 869    file_name: [18]u8,
 870
 871    pub fn getFileName(self: *const FileDefinition) []const u8 {
 872        const len = std.mem.indexOfScalar(u8, &self.file_name, @as(u8, 0)) orelse self.file_name.len;
 873        return self.file_name[0..len];
 874    }
 875};
 876
 877pub const WeakExternalDefinition = struct {
 878    /// The symbol-table index of sym2, the symbol to be linked if sym1 is not found.
 879    tag_index: u32,
 880
 881    /// A value of IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY indicates that no library search for sym1 should be performed.
 882    /// A value of IMAGE_WEAK_EXTERN_SEARCH_LIBRARY indicates that a library search for sym1 should be performed.
 883    /// A value of IMAGE_WEAK_EXTERN_SEARCH_ALIAS indicates that sym1 is an alias for sym2.
 884    flag: WeakExternalFlag,
 885
 886    unused: [10]u8,
 887
 888    pub fn sizeOf() usize {
 889        return 18;
 890    }
 891};
 892
 893// https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/km/ntimage.h
 894pub const WeakExternalFlag = enum(u32) {
 895    SEARCH_NOLIBRARY = 1,
 896    SEARCH_LIBRARY = 2,
 897    SEARCH_ALIAS = 3,
 898    ANTI_DEPENDENCY = 4,
 899    _,
 900};
 901
 902pub const ComdatSelection = enum(u8) {
 903    /// Not a COMDAT section.
 904    NONE = 0,
 905
 906    /// If this symbol is already defined, the linker issues a "multiply defined symbol" error.
 907    NODUPLICATES = 1,
 908
 909    /// Any section that defines the same COMDAT symbol can be linked; the rest are removed.
 910    ANY = 2,
 911
 912    /// The linker chooses an arbitrary section among the definitions for this symbol.
 913    /// If all definitions are not the same size, a "multiply defined symbol" error is issued.
 914    SAME_SIZE = 3,
 915
 916    /// The linker chooses an arbitrary section among the definitions for this symbol.
 917    /// If all definitions do not match exactly, a "multiply defined symbol" error is issued.
 918    EXACT_MATCH = 4,
 919
 920    /// The section is linked if a certain other COMDAT section is linked.
 921    /// This other section is indicated by the Number field of the auxiliary symbol record for the section definition.
 922    /// This setting is useful for definitions that have components in multiple sections
 923    /// (for example, code in one and data in another), but where all must be linked or discarded as a set.
 924    /// The other section this section is associated with must be a COMDAT section, which can be another
 925    /// associative COMDAT section. An associative COMDAT section's section association chain can't form a loop.
 926    /// The section association chain must eventually come to a COMDAT section that doesn't have IMAGE_COMDAT_SELECT_ASSOCIATIVE set.
 927    ASSOCIATIVE = 5,
 928
 929    /// The linker chooses the largest definition from among all of the definitions for this symbol.
 930    /// If multiple definitions have this size, the choice between them is arbitrary.
 931    LARGEST = 6,
 932
 933    _,
 934};
 935
 936pub const DebugInfoDefinition = struct {
 937    unused_1: [4]u8,
 938
 939    /// The actual ordinal line number (1, 2, 3, and so on) within the source file, corresponding to the .bf or .ef record.
 940    linenumber: u16,
 941
 942    unused_2: [6]u8,
 943
 944    /// The symbol-table index of the next .bf symbol record.
 945    /// If the function is the last in the symbol table, this field is set to zero.
 946    /// It is not used for .ef records.
 947    pointer_to_next_function: u32,
 948
 949    unused_3: [2]u8,
 950};
 951
 952pub const Error = error{
 953    InvalidPEMagic,
 954    InvalidPEHeader,
 955    InvalidMachine,
 956    MissingPEHeader,
 957    MissingCoffSection,
 958    MissingStringTable,
 959};
 960
 961// Official documentation of the format: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
 962pub const Coff = struct {
 963    data: []const u8,
 964    // Set if `data` is backed by the image as loaded by the loader
 965    is_loaded: bool,
 966    is_image: bool,
 967    coff_header_offset: usize,
 968
 969    guid: [16]u8 = undefined,
 970    age: u32 = undefined,
 971
 972    // The lifetime of `data` must be longer than the lifetime of the returned Coff
 973    pub fn init(data: []const u8, is_loaded: bool) error{ EndOfStream, MissingPEHeader }!Coff {
 974        const pe_pointer_offset = 0x3C;
 975        const pe_magic = "PE\x00\x00";
 976
 977        if (data.len < pe_pointer_offset + 4) return error.EndOfStream;
 978        const header_offset = mem.readInt(u32, data[pe_pointer_offset..][0..4], .little);
 979        if (data.len < header_offset + 4) return error.EndOfStream;
 980        const is_image = mem.eql(u8, data[header_offset..][0..4], pe_magic);
 981
 982        const coff: Coff = .{
 983            .data = data,
 984            .is_image = is_image,
 985            .is_loaded = is_loaded,
 986            .coff_header_offset = o: {
 987                if (is_image) break :o header_offset + 4;
 988                break :o header_offset;
 989            },
 990        };
 991
 992        // Do some basic validation upfront
 993        if (is_image) {
 994            const coff_header = coff.getHeader();
 995            if (coff_header.size_of_optional_header == 0) return error.MissingPEHeader;
 996        }
 997
 998        // JK: we used to check for architecture here and throw an error if not x86 or derivative.
 999        // However I am willing to take a leap of faith and let aarch64 have a shot also.
1000
1001        return coff;
1002    }
1003
1004    pub fn getPdbPath(self: *Coff) !?[]const u8 {
1005        assert(self.is_image);
1006
1007        const data_dirs = self.getDataDirectories();
1008        if (@intFromEnum(IMAGE.DIRECTORY_ENTRY.DEBUG) >= data_dirs.len) return null;
1009
1010        const debug_dir = data_dirs[@intFromEnum(IMAGE.DIRECTORY_ENTRY.DEBUG)];
1011        var reader: std.Io.Reader = .fixed(self.data);
1012
1013        if (self.is_loaded) {
1014            reader.seek = debug_dir.virtual_address;
1015        } else {
1016            // Find what section the debug_dir is in, in order to convert the RVA to a file offset
1017            for (self.getSectionHeaders()) |*sect| {
1018                if (debug_dir.virtual_address >= sect.virtual_address and debug_dir.virtual_address < sect.virtual_address + sect.virtual_size) {
1019                    reader.seek = sect.pointer_to_raw_data + (debug_dir.virtual_address - sect.virtual_address);
1020                    break;
1021                }
1022            } else return error.InvalidDebugDirectory;
1023        }
1024
1025        // Find the correct DebugDirectoryEntry, and where its data is stored.
1026        // It can be in any section.
1027        const debug_dir_entry_count = debug_dir.size / @sizeOf(DebugDirectoryEntry);
1028        var i: u32 = 0;
1029        while (i < debug_dir_entry_count) : (i += 1) {
1030            const debug_dir_entry = try reader.takeStruct(DebugDirectoryEntry, .little);
1031            if (debug_dir_entry.type == .CODEVIEW) {
1032                const dir_offset = if (self.is_loaded) debug_dir_entry.address_of_raw_data else debug_dir_entry.pointer_to_raw_data;
1033                reader.seek = dir_offset;
1034                break;
1035            }
1036        } else return null;
1037
1038        const code_view_signature = try reader.takeArray(4);
1039        // 'RSDS' indicates PDB70 format, used by lld.
1040        if (!mem.eql(u8, code_view_signature, "RSDS"))
1041            return error.InvalidPEMagic;
1042        try reader.readSliceAll(self.guid[0..]);
1043        self.age = try reader.takeInt(u32, .little);
1044
1045        // Finally read the null-terminated string.
1046        const start = reader.seek;
1047        const len = std.mem.indexOfScalar(u8, self.data[start..], 0) orelse return null;
1048        return self.data[start .. start + len];
1049    }
1050
1051    pub fn getHeader(self: Coff) Header {
1052        return @as(*align(1) const Header, @ptrCast(self.data[self.coff_header_offset..][0..@sizeOf(Header)])).*;
1053    }
1054
1055    pub fn getOptionalHeader(self: Coff) OptionalHeader {
1056        assert(self.is_image);
1057        const offset = self.coff_header_offset + @sizeOf(Header);
1058        return @as(*align(1) const OptionalHeader, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader)])).*;
1059    }
1060
1061    pub fn getOptionalHeader32(self: Coff) OptionalHeader.PE32 {
1062        assert(self.is_image);
1063        const offset = self.coff_header_offset + @sizeOf(Header);
1064        return @as(*align(1) const OptionalHeader.PE32, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader.PE32)])).*;
1065    }
1066
1067    pub fn getOptionalHeader64(self: Coff) OptionalHeader.@"PE32+" {
1068        assert(self.is_image);
1069        const offset = self.coff_header_offset + @sizeOf(Header);
1070        return @as(*align(1) const OptionalHeader.@"PE32+", @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader.@"PE32+")])).*;
1071    }
1072
1073    pub fn getImageBase(self: Coff) u64 {
1074        const hdr = self.getOptionalHeader();
1075        return switch (@intFromEnum(hdr.magic)) {
1076            IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().image_base,
1077            IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().image_base,
1078            else => unreachable, // We assume we have validated the header already
1079        };
1080    }
1081
1082    pub fn getNumberOfDataDirectories(self: Coff) u32 {
1083        const hdr = self.getOptionalHeader();
1084        return switch (@intFromEnum(hdr.magic)) {
1085            IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().number_of_rva_and_sizes,
1086            IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().number_of_rva_and_sizes,
1087            else => unreachable, // We assume we have validated the header already
1088        };
1089    }
1090
1091    pub fn getDataDirectories(self: *const Coff) []align(1) const ImageDataDirectory {
1092        const hdr = self.getOptionalHeader();
1093        const size: usize = switch (@intFromEnum(hdr.magic)) {
1094            IMAGE_NT_OPTIONAL_HDR32_MAGIC => @sizeOf(OptionalHeader.PE32),
1095            IMAGE_NT_OPTIONAL_HDR64_MAGIC => @sizeOf(OptionalHeader.@"PE32+"),
1096            else => unreachable, // We assume we have validated the header already
1097        };
1098        const offset = self.coff_header_offset + @sizeOf(Header) + size;
1099        return @as([*]align(1) const ImageDataDirectory, @ptrCast(self.data[offset..]))[0..self.getNumberOfDataDirectories()];
1100    }
1101
1102    pub fn getSymtab(self: *const Coff) ?Symtab {
1103        const coff_header = self.getHeader();
1104        if (coff_header.pointer_to_symbol_table == 0) return null;
1105
1106        const offset = coff_header.pointer_to_symbol_table;
1107        const size = coff_header.number_of_symbols * Symbol.sizeOf();
1108        return .{ .buffer = self.data[offset..][0..size] };
1109    }
1110
1111    pub fn getStrtab(self: *const Coff) error{InvalidStrtabSize}!?Strtab {
1112        const coff_header = self.getHeader();
1113        if (coff_header.pointer_to_symbol_table == 0) return null;
1114
1115        const offset = coff_header.pointer_to_symbol_table + Symbol.sizeOf() * coff_header.number_of_symbols;
1116        const size = mem.readInt(u32, self.data[offset..][0..4], .little);
1117        if ((offset + size) > self.data.len) return error.InvalidStrtabSize;
1118
1119        return Strtab{ .buffer = self.data[offset..][0..size] };
1120    }
1121
1122    pub fn strtabRequired(self: *const Coff) bool {
1123        for (self.getSectionHeaders()) |*sect_hdr| if (sect_hdr.getName() == null) return true;
1124        return false;
1125    }
1126
1127    pub fn getSectionHeaders(self: *const Coff) []align(1) const SectionHeader {
1128        const coff_header = self.getHeader();
1129        const offset = self.coff_header_offset + @sizeOf(Header) + coff_header.size_of_optional_header;
1130        return @as([*]align(1) const SectionHeader, @ptrCast(self.data.ptr + offset))[0..coff_header.number_of_sections];
1131    }
1132
1133    pub fn getSectionHeadersAlloc(self: *const Coff, allocator: mem.Allocator) ![]SectionHeader {
1134        const section_headers = self.getSectionHeaders();
1135        const out_buff = try allocator.alloc(SectionHeader, section_headers.len);
1136        for (out_buff, 0..) |*section_header, i| {
1137            section_header.* = section_headers[i];
1138        }
1139
1140        return out_buff;
1141    }
1142
1143    pub fn getSectionName(self: *const Coff, sect_hdr: *align(1) const SectionHeader) error{InvalidStrtabSize}![]const u8 {
1144        const name = sect_hdr.getName() orelse blk: {
1145            const strtab = (try self.getStrtab()).?;
1146            const name_offset = sect_hdr.getNameOffset().?;
1147            break :blk strtab.get(name_offset);
1148        };
1149        return name;
1150    }
1151
1152    pub fn getSectionByName(self: *const Coff, comptime name: []const u8) ?*align(1) const SectionHeader {
1153        for (self.getSectionHeaders()) |*sect| {
1154            const section_name = self.getSectionName(sect) catch |e| switch (e) {
1155                error.InvalidStrtabSize => continue, //ignore invalid(?) strtab entries - see also GitHub issue #15238
1156            };
1157            if (mem.eql(u8, section_name, name)) {
1158                return sect;
1159            }
1160        }
1161        return null;
1162    }
1163
1164    pub fn getSectionData(self: *const Coff, sec: *align(1) const SectionHeader) []const u8 {
1165        const offset = if (self.is_loaded) sec.virtual_address else sec.pointer_to_raw_data;
1166        return self.data[offset..][0..sec.virtual_size];
1167    }
1168
1169    pub fn getSectionDataAlloc(self: *const Coff, sec: *align(1) const SectionHeader, allocator: mem.Allocator) ![]u8 {
1170        const section_data = self.getSectionData(sec);
1171        return allocator.dupe(u8, section_data);
1172    }
1173};
1174
1175pub const Symtab = struct {
1176    buffer: []const u8,
1177
1178    pub fn len(self: Symtab) usize {
1179        return @divExact(self.buffer.len, Symbol.sizeOf());
1180    }
1181
1182    pub const Tag = enum {
1183        symbol,
1184        debug_info,
1185        func_def,
1186        weak_ext,
1187        file_def,
1188        sect_def,
1189    };
1190
1191    pub const Record = union(Tag) {
1192        symbol: Symbol,
1193        debug_info: DebugInfoDefinition,
1194        func_def: FunctionDefinition,
1195        weak_ext: WeakExternalDefinition,
1196        file_def: FileDefinition,
1197        sect_def: SectionDefinition,
1198    };
1199
1200    /// Lives as long as Symtab instance.
1201    pub fn at(self: Symtab, index: usize, tag: Tag) Record {
1202        const offset = index * Symbol.sizeOf();
1203        const raw = self.buffer[offset..][0..Symbol.sizeOf()];
1204        return switch (tag) {
1205            .symbol => .{ .symbol = asSymbol(raw) },
1206            .debug_info => .{ .debug_info = asDebugInfo(raw) },
1207            .func_def => .{ .func_def = asFuncDef(raw) },
1208            .weak_ext => .{ .weak_ext = asWeakExtDef(raw) },
1209            .file_def => .{ .file_def = asFileDef(raw) },
1210            .sect_def => .{ .sect_def = asSectDef(raw) },
1211        };
1212    }
1213
1214    fn asSymbol(raw: []const u8) Symbol {
1215        return .{
1216            .name = raw[0..8].*,
1217            .value = mem.readInt(u32, raw[8..12], .little),
1218            .section_number = @as(SectionNumber, @enumFromInt(mem.readInt(u16, raw[12..14], .little))),
1219            .type = @as(SymType, @bitCast(mem.readInt(u16, raw[14..16], .little))),
1220            .storage_class = @as(StorageClass, @enumFromInt(raw[16])),
1221            .number_of_aux_symbols = raw[17],
1222        };
1223    }
1224
1225    fn asDebugInfo(raw: []const u8) DebugInfoDefinition {
1226        return .{
1227            .unused_1 = raw[0..4].*,
1228            .linenumber = mem.readInt(u16, raw[4..6], .little),
1229            .unused_2 = raw[6..12].*,
1230            .pointer_to_next_function = mem.readInt(u32, raw[12..16], .little),
1231            .unused_3 = raw[16..18].*,
1232        };
1233    }
1234
1235    fn asFuncDef(raw: []const u8) FunctionDefinition {
1236        return .{
1237            .tag_index = mem.readInt(u32, raw[0..4], .little),
1238            .total_size = mem.readInt(u32, raw[4..8], .little),
1239            .pointer_to_linenumber = mem.readInt(u32, raw[8..12], .little),
1240            .pointer_to_next_function = mem.readInt(u32, raw[12..16], .little),
1241            .unused = raw[16..18].*,
1242        };
1243    }
1244
1245    fn asWeakExtDef(raw: []const u8) WeakExternalDefinition {
1246        return .{
1247            .tag_index = mem.readInt(u32, raw[0..4], .little),
1248            .flag = @as(WeakExternalFlag, @enumFromInt(mem.readInt(u32, raw[4..8], .little))),
1249            .unused = raw[8..18].*,
1250        };
1251    }
1252
1253    fn asFileDef(raw: []const u8) FileDefinition {
1254        return .{
1255            .file_name = raw[0..18].*,
1256        };
1257    }
1258
1259    fn asSectDef(raw: []const u8) SectionDefinition {
1260        return .{
1261            .length = mem.readInt(u32, raw[0..4], .little),
1262            .number_of_relocations = mem.readInt(u16, raw[4..6], .little),
1263            .number_of_linenumbers = mem.readInt(u16, raw[6..8], .little),
1264            .checksum = mem.readInt(u32, raw[8..12], .little),
1265            .number = mem.readInt(u16, raw[12..14], .little),
1266            .selection = @as(ComdatSelection, @enumFromInt(raw[14])),
1267            .unused = raw[15..18].*,
1268        };
1269    }
1270
1271    pub const Slice = struct {
1272        buffer: []const u8,
1273        num: usize,
1274        count: usize = 0,
1275
1276        /// Lives as long as Symtab instance.
1277        pub fn next(self: *Slice) ?Symbol {
1278            if (self.count >= self.num) return null;
1279            const sym = asSymbol(self.buffer[0..Symbol.sizeOf()]);
1280            self.count += 1;
1281            self.buffer = self.buffer[Symbol.sizeOf()..];
1282            return sym;
1283        }
1284    };
1285
1286    pub fn slice(self: Symtab, start: usize, end: ?usize) Slice {
1287        const offset = start * Symbol.sizeOf();
1288        const llen = if (end) |e| e * Symbol.sizeOf() else self.buffer.len;
1289        const num = @divExact(llen - offset, Symbol.sizeOf());
1290        return Slice{ .buffer = self.buffer[offset..][0..llen], .num = num };
1291    }
1292};
1293
1294pub const Strtab = struct {
1295    buffer: []const u8,
1296
1297    pub fn get(self: Strtab, off: u32) []const u8 {
1298        assert(off < self.buffer.len);
1299        return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.buffer.ptr + off)), 0);
1300    }
1301};
1302
1303pub const ImportHeader = extern struct {
1304    /// Must be IMAGE_FILE_MACHINE_UNKNOWN
1305    sig1: IMAGE.FILE.MACHINE = .UNKNOWN,
1306    /// Must be 0xFFFF
1307    sig2: u16 = 0xFFFF,
1308    version: u16,
1309    machine: IMAGE.FILE.MACHINE,
1310    time_date_stamp: u32,
1311    size_of_data: u32,
1312    hint: u16,
1313    types: packed struct(u16) {
1314        type: ImportType,
1315        name_type: ImportNameType,
1316        reserved: u11,
1317    },
1318};
1319
1320pub const ImportType = enum(u2) {
1321    /// Executable code.
1322    CODE = 0,
1323    /// Data.
1324    DATA = 1,
1325    /// Specified as CONST in .def file.
1326    CONST = 2,
1327    _,
1328};
1329
1330pub const ImportNameType = enum(u3) {
1331    /// The import is by ordinal. This indicates that the value in the Ordinal/Hint
1332    /// field of the import header is the import's ordinal. If this constant is not
1333    /// specified, then the Ordinal/Hint field should always be interpreted as the import's hint.
1334    ORDINAL = 0,
1335    /// The import name is identical to the public symbol name.
1336    NAME = 1,
1337    /// The import name is the public symbol name, but skipping the leading ?, @, or optionally _.
1338    NAME_NOPREFIX = 2,
1339    /// The import name is the public symbol name, but skipping the leading ?, @, or optionally _,
1340    /// and truncating at the first @.
1341    NAME_UNDECORATE = 3,
1342    /// https://github.com/llvm/llvm-project/pull/83211
1343    NAME_EXPORTAS = 4,
1344    _,
1345};
1346
1347pub const Relocation = extern struct {
1348    virtual_address: u32,
1349    symbol_table_index: u32,
1350    type: u16,
1351};
1352
1353pub const IMAGE = struct {
1354    pub const DIRECTORY_ENTRY = enum(u32) {
1355        /// Export Directory
1356        EXPORT = 0,
1357        /// Import Directory
1358        IMPORT = 1,
1359        /// Resource Directory
1360        RESOURCE = 2,
1361        /// Exception Directory
1362        EXCEPTION = 3,
1363        /// Security Directory
1364        SECURITY = 4,
1365        /// Base Relocation Table
1366        BASERELOC = 5,
1367        /// Debug Directory
1368        DEBUG = 6,
1369        /// Architecture Specific Data
1370        ARCHITECTURE = 7,
1371        /// RVA of GP
1372        GLOBALPTR = 8,
1373        /// TLS Directory
1374        TLS = 9,
1375        /// Load Configuration Directory
1376        LOAD_CONFIG = 10,
1377        /// Bound Import Directory in headers
1378        BOUND_IMPORT = 11,
1379        /// Import Address Table
1380        IAT = 12,
1381        /// Delay Load Import Descriptors
1382        DELAY_IMPORT = 13,
1383        /// COM Runtime descriptor
1384        COM_DESCRIPTOR = 14,
1385        /// must be zero
1386        RESERVED = 15,
1387        _,
1388
1389        pub const len = @typeInfo(IMAGE.DIRECTORY_ENTRY).@"enum".fields.len;
1390    };
1391
1392    pub const FILE = struct {
1393        /// Machine Types
1394        /// The Machine field has one of the following values, which specify the CPU type.
1395        /// An image file can be run only on the specified machine or on a system that emulates the specified machine.
1396        pub const MACHINE = enum(u16) {
1397            /// The content of this field is assumed to be applicable to any machine type
1398            UNKNOWN = 0x0,
1399            /// Alpha AXP, 32-bit address space
1400            ALPHA = 0x184,
1401            /// Alpha 64, 64-bit address space
1402            ALPHA64 = 0x284,
1403            /// Matsushita AM33
1404            AM33 = 0x1d3,
1405            /// x64
1406            AMD64 = 0x8664,
1407            /// ARM little endian
1408            ARM = 0x1c0,
1409            /// ARM64 little endian
1410            ARM64 = 0xaa64,
1411            /// ABI that enables interoperability between native ARM64 and emulated x64 code.
1412            ARM64EC = 0xA641,
1413            /// Binary format that allows both native ARM64 and ARM64EC code to coexist in the same file.
1414            ARM64X = 0xA64E,
1415            /// ARM Thumb-2 little endian
1416            ARMNT = 0x1c4,
1417            /// EFI byte code
1418            EBC = 0xebc,
1419            /// Intel 386 or later processors and compatible processors
1420            I386 = 0x14c,
1421            /// Intel Itanium processor family
1422            IA64 = 0x200,
1423            /// LoongArch 32-bit processor family
1424            LOONGARCH32 = 0x6232,
1425            /// LoongArch 64-bit processor family
1426            LOONGARCH64 = 0x6264,
1427            /// Mitsubishi M32R little endian
1428            M32R = 0x9041,
1429            /// MIPS16
1430            MIPS16 = 0x266,
1431            /// MIPS with FPU
1432            MIPSFPU = 0x366,
1433            /// MIPS16 with FPU
1434            MIPSFPU16 = 0x466,
1435            /// Power PC little endian
1436            POWERPC = 0x1f0,
1437            /// Power PC with floating point support
1438            POWERPCFP = 0x1f1,
1439            /// MIPS I compatible 32-bit big endian
1440            R3000BE = 0x160,
1441            /// MIPS I compatible 32-bit little endian
1442            R3000 = 0x162,
1443            /// MIPS III compatible 64-bit little endian
1444            R4000 = 0x166,
1445            /// MIPS IV compatible 64-bit little endian
1446            R10000 = 0x168,
1447            /// RISC-V 32-bit address space
1448            RISCV32 = 0x5032,
1449            /// RISC-V 64-bit address space
1450            RISCV64 = 0x5064,
1451            /// RISC-V 128-bit address space
1452            RISCV128 = 0x5128,
1453            /// Hitachi SH3
1454            SH3 = 0x1a2,
1455            /// Hitachi SH3 DSP
1456            SH3DSP = 0x1a3,
1457            /// Hitachi SH4
1458            SH4 = 0x1a6,
1459            /// Hitachi SH5
1460            SH5 = 0x1a8,
1461            /// Thumb
1462            THUMB = 0x1c2,
1463            /// MIPS little-endian WCE v2
1464            WCEMIPSV2 = 0x169,
1465            _,
1466            /// AXP 64 (Same as Alpha 64)
1467            pub const AXP64: IMAGE.FILE.MACHINE = .ALPHA64;
1468        };
1469    };
1470
1471    pub const REL = struct {
1472        /// x64 Processors
1473        /// The following relocation type indicators are defined for x64 and compatible processors.
1474        pub const AMD64 = enum(u16) {
1475            /// The relocation is ignored.
1476            ABSOLUTE = 0x0000,
1477            /// The 64-bit VA of the relocation target.
1478            ADDR64 = 0x0001,
1479            /// The 32-bit VA of the relocation target.
1480            ADDR32 = 0x0002,
1481            /// The 32-bit address without an image base (RVA).
1482            ADDR32NB = 0x0003,
1483            /// The 32-bit relative address from the byte following the relocation.
1484            REL32 = 0x0004,
1485            /// The 32-bit address relative to byte distance 1 from the relocation.
1486            REL32_1 = 0x0005,
1487            /// The 32-bit address relative to byte distance 2 from the relocation.
1488            REL32_2 = 0x0006,
1489            /// The 32-bit address relative to byte distance 3 from the relocation.
1490            REL32_3 = 0x0007,
1491            /// The 32-bit address relative to byte distance 4 from the relocation.
1492            REL32_4 = 0x0008,
1493            /// The 32-bit address relative to byte distance 5 from the relocation.
1494            REL32_5 = 0x0009,
1495            /// The 16-bit section index of the section that contains the target.
1496            /// This is used to support debugging information.
1497            SECTION = 0x000A,
1498            /// The 32-bit offset of the target from the beginning of its section.
1499            /// This is used to support debugging information and static thread local storage.
1500            SECREL = 0x000B,
1501            /// A 7-bit unsigned offset from the base of the section that contains the target.
1502            SECREL7 = 0x000C,
1503            /// CLR tokens.
1504            TOKEN = 0x000D,
1505            /// A 32-bit signed span-dependent value emitted into the object.
1506            SREL32 = 0x000E,
1507            /// A pair that must immediately follow every span-dependent value.
1508            PAIR = 0x000F,
1509            /// A 32-bit signed span-dependent value that is applied at link time.
1510            SSPAN32 = 0x0010,
1511            _,
1512        };
1513
1514        /// ARM Processors
1515        /// The following relocation type indicators are defined for ARM processors.
1516        pub const ARM = enum(u16) {
1517            /// The relocation is ignored.
1518            ABSOLUTE = 0x0000,
1519            /// The 32-bit VA of the target.
1520            ADDR32 = 0x0001,
1521            /// The 32-bit RVA of the target.
1522            ADDR32NB = 0x0002,
1523            /// The 24-bit relative displacement to the target.
1524            BRANCH24 = 0x0003,
1525            /// The reference to a subroutine call.
1526            /// The reference consists of two 16-bit instructions with 11-bit offsets.
1527            BRANCH11 = 0x0004,
1528            /// The 32-bit relative address from the byte following the relocation.
1529            REL32 = 0x000A,
1530            /// The 16-bit section index of the section that contains the target.
1531            /// This is used to support debugging information.
1532            SECTION = 0x000E,
1533            /// The 32-bit offset of the target from the beginning of its section.
1534            /// This is used to support debugging information and static thread local storage.
1535            SECREL = 0x000F,
1536            /// The 32-bit VA of the target.
1537            /// This relocation is applied using a MOVW instruction for the low 16 bits followed by a MOVT for the high 16 bits.
1538            MOV32 = 0x0010,
1539            /// The 32-bit VA of the target.
1540            /// This relocation is applied using a MOVW instruction for the low 16 bits followed by a MOVT for the high 16 bits.
1541            THUMB_MOV32 = 0x0011,
1542            /// The instruction is fixed up with the 21-bit relative displacement to the 2-byte aligned target.
1543            /// The least significant bit of the displacement is always zero and is not stored.
1544            /// This relocation corresponds to a Thumb-2 32-bit conditional B instruction.
1545            THUMB_BRANCH20 = 0x0012,
1546            Unused = 0x0013,
1547            /// The instruction is fixed up with the 25-bit relative displacement to the 2-byte aligned target.
1548            /// The least significant bit of the displacement is zero and is not stored.This relocation corresponds to a Thumb-2 B instruction.
1549            THUMB_BRANCH24 = 0x0014,
1550            /// The instruction is fixed up with the 25-bit relative displacement to the 4-byte aligned target.
1551            /// The low 2 bits of the displacement are zero and are not stored.
1552            /// This relocation corresponds to a Thumb-2 BLX instruction.
1553            THUMB_BLX23 = 0x0015,
1554            /// The relocation is valid only when it immediately follows a ARM_REFHI or THUMB_REFHI.
1555            /// Its SymbolTableIndex contains a displacement and not an index into the symbol table.
1556            PAIR = 0x0016,
1557            _,
1558        };
1559
1560        /// ARM64 Processors
1561        /// The following relocation type indicators are defined for ARM64 processors.
1562        pub const ARM64 = enum(u16) {
1563            /// The relocation is ignored.
1564            ABSOLUTE = 0x0000,
1565            /// The 32-bit VA of the target.
1566            ADDR32 = 0x0001,
1567            /// The 32-bit RVA of the target.
1568            ADDR32NB = 0x0002,
1569            /// The 26-bit relative displacement to the target, for B and BL instructions.
1570            BRANCH26 = 0x0003,
1571            /// The page base of the target, for ADRP instruction.
1572            PAGEBASE_REL21 = 0x0004,
1573            /// The 12-bit relative displacement to the target, for instruction ADR
1574            REL21 = 0x0005,
1575            /// The 12-bit page offset of the target, for instructions ADD/ADDS (immediate) with zero shift.
1576            PAGEOFFSET_12A = 0x0006,
1577            /// The 12-bit page offset of the target, for instruction LDR (indexed, unsigned immediate).
1578            PAGEOFFSET_12L = 0x0007,
1579            /// The 32-bit offset of the target from the beginning of its section.
1580            /// This is used to support debugging information and static thread local storage.
1581            SECREL = 0x0008,
1582            /// Bit 0:11 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift.
1583            SECREL_LOW12A = 0x0009,
1584            /// Bit 12:23 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift.
1585            SECREL_HIGH12A = 0x000A,
1586            /// Bit 0:11 of section offset of the target, for instruction LDR (indexed, unsigned immediate).
1587            SECREL_LOW12L = 0x000B,
1588            /// CLR token.
1589            TOKEN = 0x000C,
1590            /// The 16-bit section index of the section that contains the target.
1591            /// This is used to support debugging information.
1592            SECTION = 0x000D,
1593            /// The 64-bit VA of the relocation target.
1594            ADDR64 = 0x000E,
1595            /// The 19-bit offset to the relocation target, for conditional B instruction.
1596            BRANCH19 = 0x000F,
1597            /// The 14-bit offset to the relocation target, for instructions TBZ and TBNZ.
1598            BRANCH14 = 0x0010,
1599            /// The 32-bit relative address from the byte following the relocation.
1600            REL32 = 0x0011,
1601            _,
1602        };
1603
1604        /// Hitachi SuperH Processors
1605        /// The following relocation type indicators are defined for SH3 and SH4 processors.
1606        /// SH5-specific relocations are noted as SHM (SH Media).
1607        pub const SH = enum(u16) {
1608            /// The relocation is ignored.
1609            @"3_ABSOLUTE" = 0x0000,
1610            /// A reference to the 16-bit location that contains the VA of the target symbol.
1611            @"3_DIRECT16" = 0x0001,
1612            /// The 32-bit VA of the target symbol.
1613            @"3_DIRECT32" = 0x0002,
1614            /// A reference to the 8-bit location that contains the VA of the target symbol.
1615            @"3_DIRECT8" = 0x0003,
1616            /// A reference to the 8-bit instruction that contains the effective 16-bit VA of the target symbol.
1617            @"3_DIRECT8_WORD" = 0x0004,
1618            /// A reference to the 8-bit instruction that contains the effective 32-bit VA of the target symbol.
1619            @"3_DIRECT8_LONG" = 0x0005,
1620            /// A reference to the 8-bit location whose low 4 bits contain the VA of the target symbol.
1621            @"3_DIRECT4" = 0x0006,
1622            /// A reference to the 8-bit instruction whose low 4 bits contain the effective 16-bit VA of the target symbol.
1623            @"3_DIRECT4_WORD" = 0x0007,
1624            /// A reference to the 8-bit instruction whose low 4 bits contain the effective 32-bit VA of the target symbol.
1625            @"3_DIRECT4_LONG" = 0x0008,
1626            /// A reference to the 8-bit instruction that contains the effective 16-bit relative offset of the target symbol.
1627            @"3_PCREL8_WORD" = 0x0009,
1628            /// A reference to the 8-bit instruction that contains the effective 32-bit relative offset of the target symbol.
1629            @"3_PCREL8_LONG" = 0x000A,
1630            /// A reference to the 16-bit instruction whose low 12 bits contain the effective 16-bit relative offset of the target symbol.
1631            @"3_PCREL12_WORD" = 0x000B,
1632            /// A reference to a 32-bit location that is the VA of the section that contains the target symbol.
1633            @"3_STARTOF_SECTION" = 0x000C,
1634            /// A reference to the 32-bit location that is the size of the section that contains the target symbol.
1635            @"3_SIZEOF_SECTION" = 0x000D,
1636            /// The 16-bit section index of the section that contains the target.
1637            /// This is used to support debugging information.
1638            @"3_SECTION" = 0x000E,
1639            /// The 32-bit offset of the target from the beginning of its section.
1640            /// This is used to support debugging information and static thread local storage.
1641            @"3_SECREL" = 0x000F,
1642            /// The 32-bit RVA of the target symbol.
1643            @"3_DIRECT32_NB" = 0x0010,
1644            /// GP relative.
1645            @"3_GPREL4_LONG" = 0x0011,
1646            /// CLR token.
1647            @"3_TOKEN" = 0x0012,
1648            /// The offset from the current instruction in longwords.
1649            /// If the NOMODE bit is not set, insert the inverse of the low bit at bit 32 to select PTA or PTB.
1650            M_PCRELPT = 0x0013,
1651            /// The low 16 bits of the 32-bit address.
1652            M_REFLO = 0x0014,
1653            /// The high 16 bits of the 32-bit address.
1654            M_REFHALF = 0x0015,
1655            /// The low 16 bits of the relative address.
1656            M_RELLO = 0x0016,
1657            /// The high 16 bits of the relative address.
1658            M_RELHALF = 0x0017,
1659            /// The relocation is valid only when it immediately follows a REFHALF, RELHALF, or RELLO relocation.
1660            /// The SymbolTableIndex field of the relocation contains a displacement and not an index into the symbol table.
1661            M_PAIR = 0x0018,
1662            /// The relocation ignores section mode.
1663            M_NOMODE = 0x8000,
1664            _,
1665        };
1666
1667        /// IBM PowerPC Processors
1668        /// The following relocation type indicators are defined for PowerPC processors.
1669        pub const PPC = enum(u16) {
1670            /// The relocation is ignored.
1671            ABSOLUTE = 0x0000,
1672            /// The 64-bit VA of the target.
1673            ADDR64 = 0x0001,
1674            /// The 32-bit VA of the target.
1675            ADDR32 = 0x0002,
1676            /// The low 24 bits of the VA of the target.
1677            /// This is valid only when the target symbol is absolute and can be sign-extended to its original value.
1678            ADDR24 = 0x0003,
1679            /// The low 16 bits of the target's VA.
1680            ADDR16 = 0x0004,
1681            /// The low 14 bits of the target's VA.
1682            /// This is valid only when the target symbol is absolute and can be sign-extended to its original value.
1683            ADDR14 = 0x0005,
1684            /// A 24-bit PC-relative offset to the symbol's location.
1685            REL24 = 0x0006,
1686            /// A 14-bit PC-relative offset to the symbol's location.
1687            REL14 = 0x0007,
1688            /// The 32-bit RVA of the target.
1689            ADDR32NB = 0x000A,
1690            /// The 32-bit offset of the target from the beginning of its section.
1691            /// This is used to support debugging information and static thread local storage.
1692            SECREL = 0x000B,
1693            /// The 16-bit section index of the section that contains the target.
1694            /// This is used to support debugging information.
1695            SECTION = 0x000C,
1696            /// The 16-bit offset of the target from the beginning of its section.
1697            /// This is used to support debugging information and static thread local storage.
1698            SECREL16 = 0x000F,
1699            /// The high 16 bits of the target's 32-bit VA.
1700            /// This is used for the first instruction in a two-instruction sequence that loads a full address.
1701            /// This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that was taken from the location that is being relocated.
1702            REFHI = 0x0010,
1703            /// The low 16 bits of the target's VA.
1704            REFLO = 0x0011,
1705            /// A relocation that is valid only when it immediately follows a REFHI or SECRELHI relocation.
1706            /// Its SymbolTableIndex contains a displacement and not an index into the symbol table.
1707            PAIR = 0x0012,
1708            /// The low 16 bits of the 32-bit offset of the target from the beginning of its section.
1709            SECRELLO = 0x0013,
1710            /// The 16-bit signed displacement of the target relative to the GP register.
1711            GPREL = 0x0015,
1712            /// The CLR token.
1713            TOKEN = 0x0016,
1714            _,
1715        };
1716
1717        /// Intel 386 Processors
1718        /// The following relocation type indicators are defined for Intel 386 and compatible processors.
1719        pub const I386 = enum(u16) {
1720            /// The relocation is ignored.
1721            ABSOLUTE = 0x0000,
1722            /// Not supported.
1723            DIR16 = 0x0001,
1724            /// Not supported.
1725            REL16 = 0x0002,
1726            /// The target's 32-bit VA.
1727            DIR32 = 0x0006,
1728            /// The target's 32-bit RVA.
1729            DIR32NB = 0x0007,
1730            /// Not supported.
1731            SEG12 = 0x0009,
1732            /// The 16-bit section index of the section that contains the target.
1733            /// This is used to support debugging information.
1734            SECTION = 0x000A,
1735            /// The 32-bit offset of the target from the beginning of its section.
1736            /// This is used to support debugging information and static thread local storage.
1737            SECREL = 0x000B,
1738            /// The CLR token.
1739            TOKEN = 0x000C,
1740            /// A 7-bit offset from the base of the section that contains the target.
1741            SECREL7 = 0x000D,
1742            /// The 32-bit relative displacement to the target.
1743            /// This supports the x86 relative branch and call instructions.
1744            REL32 = 0x0014,
1745            _,
1746        };
1747
1748        /// Intel Itanium Processor Family (IPF)
1749        /// The following relocation type indicators are defined for the Intel Itanium processor family and compatible processors.
1750        /// Note that relocations on instructions use the bundle's offset and slot number for the relocation offset.
1751        pub const IA64 = enum(u16) {
1752            /// The relocation is ignored.
1753            ABSOLUTE = 0x0000,
1754            /// The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address before it is inserted into the specified slot in the IMM14 bundle.
1755            /// The relocation target must be absolute or the image must be fixed.
1756            IMM14 = 0x0001,
1757            /// The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address before it is inserted into the specified slot in the IMM22 bundle.
1758            /// The relocation target must be absolute or the image must be fixed.
1759            IMM22 = 0x0002,
1760            /// The slot number of this relocation must be one (1).
1761            /// The relocation can be followed by an ADDEND relocation whose value is added to the target address before it is stored in all three slots of the IMM64 bundle.
1762            IMM64 = 0x0003,
1763            /// The target's 32-bit VA.
1764            /// This is supported only for /LARGEADDRESSAWARE:NO images.
1765            DIR32 = 0x0004,
1766            /// The target's 64-bit VA.
1767            DIR64 = 0x0005,
1768            /// The instruction is fixed up with the 25-bit relative displacement to the 16-bit aligned target.
1769            /// The low 4 bits of the displacement are zero and are not stored.
1770            PCREL21B = 0x0006,
1771            /// The instruction is fixed up with the 25-bit relative displacement to the 16-bit aligned target.
1772            /// The low 4 bits of the displacement, which are zero, are not stored.
1773            PCREL21M = 0x0007,
1774            /// The LSBs of this relocation's offset must contain the slot number whereas the rest is the bundle address.
1775            /// The bundle is fixed up with the 25-bit relative displacement to the 16-bit aligned target.
1776            /// The low 4 bits of the displacement are zero and are not stored.
1777            PCREL21F = 0x0008,
1778            /// The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address and then a 22-bit GP-relative offset that is calculated and applied to the GPREL22 bundle.
1779            GPREL22 = 0x0009,
1780            /// The instruction is fixed up with the 22-bit GP-relative offset to the target symbol's literal table entry.
1781            /// The linker creates this literal table entry based on this relocation and the ADDEND relocation that might follow.
1782            LTOFF22 = 0x000A,
1783            /// The 16-bit section index of the section contains the target.
1784            /// This is used to support debugging information.
1785            SECTION = 0x000B,
1786            /// The instruction is fixed up with the 22-bit offset of the target from the beginning of its section.
1787            /// This relocation can be followed immediately by an ADDEND relocation, whose Value field contains the 32-bit unsigned offset of the target from the beginning of the section.
1788            SECREL22 = 0x000C,
1789            /// The slot number for this relocation must be one (1).
1790            /// The instruction is fixed up with the 64-bit offset of the target from the beginning of its section.
1791            /// This relocation can be followed immediately by an ADDEND relocation whose Value field contains the 32-bit unsigned offset of the target from the beginning of the section.
1792            SECREL64I = 0x000D,
1793            /// The address of data to be fixed up with the 32-bit offset of the target from the beginning of its section.
1794            SECREL32 = 0x000E,
1795            /// The target's 32-bit RVA.
1796            DIR32NB = 0x0010,
1797            /// This is applied to a signed 14-bit immediate that contains the difference between two relocatable targets.
1798            /// This is a declarative field for the linker that indicates that the compiler has already emitted this value.
1799            SREL14 = 0x0011,
1800            /// This is applied to a signed 22-bit immediate that contains the difference between two relocatable targets.
1801            /// This is a declarative field for the linker that indicates that the compiler has already emitted this value.
1802            SREL22 = 0x0012,
1803            /// This is applied to a signed 32-bit immediate that contains the difference between two relocatable values.
1804            /// This is a declarative field for the linker that indicates that the compiler has already emitted this value.
1805            SREL32 = 0x0013,
1806            /// This is applied to an unsigned 32-bit immediate that contains the difference between two relocatable values.
1807            /// This is a declarative field for the linker that indicates that the compiler has already emitted this value.
1808            UREL32 = 0x0014,
1809            /// A 60-bit PC-relative fixup that always stays as a BRL instruction of an MLX bundle.
1810            PCREL60X = 0x0015,
1811            /// A 60-bit PC-relative fixup.
1812            /// If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MBB bundle with NOP.B in slot 1 and a 25-bit BR instruction (with the 4 lowest bits all zero and dropped) in slot 2.
1813            PCREL60B = 0x0016,
1814            /// A 60-bit PC-relative fixup.
1815            /// If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MFB bundle with NOP.F in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
1816            PCREL60F = 0x0017,
1817            /// A 60-bit PC-relative fixup.
1818            /// If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MIB bundle with NOP.I in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
1819            PCREL60I = 0x0018,
1820            /// A 60-bit PC-relative fixup.
1821            /// If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MMB bundle with NOP.M in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
1822            PCREL60M = 0x0019,
1823            /// A 64-bit GP-relative fixup.
1824            IMMGPREL64 = 0x001a,
1825            /// A CLR token.
1826            TOKEN = 0x001b,
1827            /// A 32-bit GP-relative fixup.
1828            GPREL32 = 0x001c,
1829            /// The relocation is valid only when it immediately follows one of the following relocations: IMM14, IMM22, IMM64, GPREL22, LTOFF22, LTOFF64, SECREL22, SECREL64I, or SECREL32.
1830            /// Its value contains the addend to apply to instructions within a bundle, not for data.
1831            ADDEND = 0x001F,
1832            _,
1833        };
1834
1835        /// MIPS Processors
1836        /// The following relocation type indicators are defined for MIPS processors.
1837        pub const MIPS = enum(u16) {
1838            /// The relocation is ignored.
1839            ABSOLUTE = 0x0000,
1840            /// The high 16 bits of the target's 32-bit VA.
1841            REFHALF = 0x0001,
1842            /// The target's 32-bit VA.
1843            REFWORD = 0x0002,
1844            /// The low 26 bits of the target's VA.
1845            /// This supports the MIPS J and JAL instructions.
1846            JMPADDR = 0x0003,
1847            /// The high 16 bits of the target's 32-bit VA.
1848            /// This is used for the first instruction in a two-instruction sequence that loads a full address.
1849            /// This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
1850            REFHI = 0x0004,
1851            /// The low 16 bits of the target's VA.
1852            REFLO = 0x0005,
1853            /// A 16-bit signed displacement of the target relative to the GP register.
1854            GPREL = 0x0006,
1855            /// The same as IMAGE_REL_MIPS_GPREL.
1856            LITERAL = 0x0007,
1857            /// The 16-bit section index of the section contains the target.
1858            /// This is used to support debugging information.
1859            SECTION = 0x000A,
1860            /// The 32-bit offset of the target from the beginning of its section.
1861            /// This is used to support debugging information and static thread local storage.
1862            SECREL = 0x000B,
1863            /// The low 16 bits of the 32-bit offset of the target from the beginning of its section.
1864            SECRELLO = 0x000C,
1865            /// The high 16 bits of the 32-bit offset of the target from the beginning of its section.
1866            /// An IMAGE_REL_MIPS_PAIR relocation must immediately follow this one.
1867            /// The SymbolTableIndex of the PAIR relocation contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
1868            SECRELHI = 0x000D,
1869            /// The low 26 bits of the target's VA.
1870            /// This supports the MIPS16 JAL instruction.
1871            JMPADDR16 = 0x0010,
1872            /// The target's 32-bit RVA.
1873            REFWORDNB = 0x0022,
1874            /// The relocation is valid only when it immediately follows a REFHI or SECRELHI relocation.
1875            /// Its SymbolTableIndex contains a displacement and not an index into the symbol table.
1876            PAIR = 0x0025,
1877            _,
1878        };
1879
1880        /// Mitsubishi M32R
1881        /// The following relocation type indicators are defined for the Mitsubishi M32R processors.
1882        pub const M32R = enum(u16) {
1883            /// The relocation is ignored.
1884            ABSOLUTE = 0x0000,
1885            /// The target's 32-bit VA.
1886            ADDR32 = 0x0001,
1887            /// The target's 32-bit RVA.
1888            ADDR32NB = 0x0002,
1889            /// The target's 24-bit VA.
1890            ADDR24 = 0x0003,
1891            /// The target's 16-bit offset from the GP register.
1892            GPREL16 = 0x0004,
1893            /// The target's 24-bit offset from the program counter (PC), shifted left by 2 bits and sign-extended
1894            PCREL24 = 0x0005,
1895            /// The target's 16-bit offset from the PC, shifted left by 2 bits and sign-extended
1896            PCREL16 = 0x0006,
1897            /// The target's 8-bit offset from the PC, shifted left by 2 bits and sign-extended
1898            PCREL8 = 0x0007,
1899            /// The 16 MSBs of the target VA.
1900            REFHALF = 0x0008,
1901            /// The 16 MSBs of the target VA, adjusted for LSB sign extension.
1902            /// This is used for the first instruction in a two-instruction sequence that loads a full 32-bit address.
1903            /// This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
1904            REFHI = 0x0009,
1905            /// The 16 LSBs of the target VA.
1906            REFLO = 0x000A,
1907            /// The relocation must follow the REFHI relocation.
1908            /// Its SymbolTableIndex contains a displacement and not an index into the symbol table.
1909            PAIR = 0x000B,
1910            /// The 16-bit section index of the section that contains the target.
1911            /// This is used to support debugging information.
1912            SECTION = 0x000C,
1913            /// The 32-bit offset of the target from the beginning of its section.
1914            /// This is used to support debugging information and static thread local storage.
1915            SECREL = 0x000D,
1916            /// The CLR token.
1917            TOKEN = 0x000E,
1918            _,
1919        };
1920    };
1921};