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