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};