| author | |
| committer | |
| log | e1f3fc6ce289502cde1e52fa946476ff8e3bcaac |
| tree | 42231ed7f2348c3c19b495bf8d4eac3acbfce21b |
| parent | d5f09f56e0327685dfcaeb889efd9d6a26461886 |
58 files changed, 3484 insertions(+), 902 deletions(-)
lib/std/Target.zig+2-2| ... | ... | @@ -1082,7 +1082,7 @@ pub fn toElfMachine(target: *const Target) std.elf.EM { |
| 1082 | 1082 | }; |
| 1083 | 1083 | } |
| 1084 | 1084 | |
| 1085 | pub fn toCoffMachine(target: *const Target) std.coff.MachineType { | |
| 1085 | pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE { | |
| 1086 | 1086 | return switch (target.cpu.arch) { |
| 1087 | 1087 | .arm => .ARM, |
| 1088 | 1088 | .thumb => .ARMNT, |
| ... | ... | @@ -1092,7 +1092,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.MachineType { |
| 1092 | 1092 | .riscv32 => .RISCV32, |
| 1093 | 1093 | .riscv64 => .RISCV64, |
| 1094 | 1094 | .x86 => .I386, |
| 1095 | .x86_64 => .X64, | |
| 1095 | .x86_64 => .AMD64, | |
| 1096 | 1096 | |
| 1097 | 1097 | .amdgcn, |
| 1098 | 1098 | .arc, |
lib/std/array_hash_map.zig+1-1| ... | ... | @@ -50,7 +50,7 @@ pub fn eqlString(a: []const u8, b: []const u8) bool { |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | 52 | pub fn hashString(s: []const u8) u32 { |
| 53 | return @as(u32, @truncate(std.hash.Wyhash.hash(0, s))); | |
| 53 | return @truncate(std.hash.Wyhash.hash(0, s)); | |
| 54 | 54 | } |
| 55 | 55 | |
| 56 | 56 | /// Deprecated in favor of `ArrayHashMapWithAllocator` (no code changes needed) |
lib/std/coff.zig+771-432| ... | ... | @@ -2,70 +2,9 @@ const std = @import("std.zig"); |
| 2 | 2 | const assert = std.debug.assert; |
| 3 | 3 | const mem = std.mem; |
| 4 | 4 | |
| 5 | pub const CoffHeaderFlags = packed struct { | |
| 6 | /// Image only, Windows CE, and Microsoft Windows NT and later. | |
| 7 | /// This indicates that the file does not contain base relocations | |
| 8 | /// and must therefore be loaded at its preferred base address. | |
| 9 | /// If the base address is not available, the loader reports an error. | |
| 10 | /// The default behavior of the linker is to strip base relocations | |
| 11 | /// from executable (EXE) files. | |
| 12 | RELOCS_STRIPPED: u1 = 0, | |
| 13 | ||
| 14 | /// Image only. This indicates that the image file is valid and can be run. | |
| 15 | /// If this flag is not set, it indicates a linker error. | |
| 16 | EXECUTABLE_IMAGE: u1 = 0, | |
| 17 | ||
| 18 | /// COFF line numbers have been removed. This flag is deprecated and should be zero. | |
| 19 | LINE_NUMS_STRIPPED: u1 = 0, | |
| 20 | ||
| 21 | /// COFF symbol table entries for local symbols have been removed. | |
| 22 | /// This flag is deprecated and should be zero. | |
| 23 | LOCAL_SYMS_STRIPPED: u1 = 0, | |
| 24 | ||
| 25 | /// Obsolete. Aggressively trim working set. | |
| 26 | /// This flag is deprecated for Windows 2000 and later and must be zero. | |
| 27 | AGGRESSIVE_WS_TRIM: u1 = 0, | |
| 28 | ||
| 29 | /// Application can handle > 2-GB addresses. | |
| 30 | LARGE_ADDRESS_AWARE: u1 = 0, | |
| 31 | ||
| 32 | /// This flag is reserved for future use. | |
| 33 | RESERVED: u1 = 0, | |
| 34 | ||
| 35 | /// Little endian: the least significant bit (LSB) precedes the | |
| 36 | /// most significant bit (MSB) in memory. This flag is deprecated and should be zero. | |
| 37 | BYTES_REVERSED_LO: u1 = 0, | |
| 38 | ||
| 39 | /// Machine is based on a 32-bit-word architecture. | |
| 40 | @"32BIT_MACHINE": u1 = 0, | |
| 41 | ||
| 42 | /// Debugging information is removed from the image file. | |
| 43 | DEBUG_STRIPPED: u1 = 0, | |
| 44 | ||
| 45 | /// If the image is on removable media, fully load it and copy it to the swap file. | |
| 46 | REMOVABLE_RUN_FROM_SWAP: u1 = 0, | |
| 47 | ||
| 48 | /// If the image is on network media, fully load it and copy it to the swap file. | |
| 49 | NET_RUN_FROM_SWAP: u1 = 0, | |
| 50 | ||
| 51 | /// The image file is a system file, not a user program. | |
| 52 | SYSTEM: u1 = 0, | |
| 53 | ||
| 54 | /// The image file is a dynamic-link library (DLL). | |
| 55 | /// Such files are considered executable files for almost all purposes, | |
| 56 | /// although they cannot be directly run. | |
| 57 | DLL: u1 = 0, | |
| 58 | ||
| 59 | /// The file should be run only on a uniprocessor machine. | |
| 60 | UP_SYSTEM_ONLY: u1 = 0, | |
| 61 | ||
| 62 | /// Big endian: the MSB precedes the LSB in memory. This flag is deprecated and should be zero. | |
| 63 | BYTES_REVERSED_HI: u1 = 0, | |
| 64 | }; | |
| 65 | ||
| 66 | pub const CoffHeader = extern struct { | |
| 5 | pub const Header = extern struct { | |
| 67 | 6 | /// The number that identifies the type of target machine. |
| 68 | machine: MachineType, | |
| 7 | machine: IMAGE.FILE.MACHINE, | |
| 69 | 8 | |
| 70 | 9 | /// The number of sections. This indicates the size of the section table, which immediately follows the headers. |
| 71 | 10 | number_of_sections: u16, |
| ... | ... | @@ -88,49 +27,110 @@ pub const CoffHeader = extern struct { |
| 88 | 27 | size_of_optional_header: u16, |
| 89 | 28 | |
| 90 | 29 | /// The flags that indicate the attributes of the file. |
| 91 | flags: CoffHeaderFlags, | |
| 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 | 92 | }; |
| 93 | 93 | |
| 94 | 94 | // OptionalHeader.magic values |
| 95 | 95 | // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx |
| 96 | pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b; | |
| 97 | pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b; | |
| 96 | pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC = @intFromEnum(OptionalHeader.Magic.PE32); | |
| 97 | pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC = @intFromEnum(OptionalHeader.Magic.@"PE32+"); | |
| 98 | 98 | |
| 99 | pub const DllFlags = packed struct { | |
| 99 | pub const DllFlags = packed struct(u16) { | |
| 100 | 100 | _reserved_0: u5 = 0, |
| 101 | 101 | |
| 102 | 102 | /// Image can handle a high entropy 64-bit virtual address space. |
| 103 | HIGH_ENTROPY_VA: u1 = 0, | |
| 103 | HIGH_ENTROPY_VA: bool = false, | |
| 104 | 104 | |
| 105 | 105 | /// DLL can be relocated at load time. |
| 106 | DYNAMIC_BASE: u1 = 0, | |
| 106 | DYNAMIC_BASE: bool = false, | |
| 107 | 107 | |
| 108 | 108 | /// Code Integrity checks are enforced. |
| 109 | FORCE_INTEGRITY: u1 = 0, | |
| 109 | FORCE_INTEGRITY: bool = false, | |
| 110 | 110 | |
| 111 | 111 | /// Image is NX compatible. |
| 112 | NX_COMPAT: u1 = 0, | |
| 112 | NX_COMPAT: bool = false, | |
| 113 | 113 | |
| 114 | 114 | /// Isolation aware, but do not isolate the image. |
| 115 | NO_ISOLATION: u1 = 0, | |
| 115 | NO_ISOLATION: bool = false, | |
| 116 | 116 | |
| 117 | 117 | /// Does not use structured exception (SE) handling. No SE handler may be called in this image. |
| 118 | NO_SEH: u1 = 0, | |
| 118 | NO_SEH: bool = false, | |
| 119 | 119 | |
| 120 | 120 | /// Do not bind the image. |
| 121 | NO_BIND: u1 = 0, | |
| 121 | NO_BIND: bool = false, | |
| 122 | 122 | |
| 123 | 123 | /// Image must execute in an AppContainer. |
| 124 | APPCONTAINER: u1 = 0, | |
| 124 | APPCONTAINER: bool = false, | |
| 125 | 125 | |
| 126 | 126 | /// A WDM driver. |
| 127 | WDM_DRIVER: u1 = 0, | |
| 127 | WDM_DRIVER: bool = false, | |
| 128 | 128 | |
| 129 | 129 | /// Image supports Control Flow Guard. |
| 130 | GUARD_CF: u1 = 0, | |
| 130 | GUARD_CF: bool = false, | |
| 131 | 131 | |
| 132 | 132 | /// Terminal Server aware. |
| 133 | TERMINAL_SERVER_AWARE: u1 = 0, | |
| 133 | TERMINAL_SERVER_AWARE: bool = false, | |
| 134 | 134 | }; |
| 135 | 135 | |
| 136 | 136 | pub const Subsystem = enum(u16) { |
| ... | ... | @@ -180,7 +180,7 @@ pub const Subsystem = enum(u16) { |
| 180 | 180 | }; |
| 181 | 181 | |
| 182 | 182 | pub const OptionalHeader = extern struct { |
| 183 | magic: u16, | |
| 183 | magic: OptionalHeader.Magic, | |
| 184 | 184 | major_linker_version: u8, |
| 185 | 185 | minor_linker_version: u8, |
| 186 | 186 | size_of_code: u32, |
| ... | ... | @@ -188,71 +188,63 @@ pub const OptionalHeader = extern struct { |
| 188 | 188 | size_of_uninitialized_data: u32, |
| 189 | 189 | address_of_entry_point: u32, |
| 190 | 190 | base_of_code: u32, |
| 191 | }; | |
| 192 | 191 | |
| 193 | pub const OptionalHeaderPE32 = extern struct { | |
| 194 | magic: u16, | |
| 195 | major_linker_version: u8, | |
| 196 | minor_linker_version: u8, | |
| 197 | size_of_code: u32, | |
| 198 | size_of_initialized_data: u32, | |
| 199 | size_of_uninitialized_data: u32, | |
| 200 | address_of_entry_point: u32, | |
| 201 | base_of_code: u32, | |
| 202 | base_of_data: u32, | |
| 203 | image_base: u32, | |
| 204 | section_alignment: u32, | |
| 205 | file_alignment: u32, | |
| 206 | major_operating_system_version: u16, | |
| 207 | minor_operating_system_version: u16, | |
| 208 | major_image_version: u16, | |
| 209 | minor_image_version: u16, | |
| 210 | major_subsystem_version: u16, | |
| 211 | minor_subsystem_version: u16, | |
| 212 | win32_version_value: u32, | |
| 213 | size_of_image: u32, | |
| 214 | size_of_headers: u32, | |
| 215 | checksum: u32, | |
| 216 | subsystem: Subsystem, | |
| 217 | dll_flags: DllFlags, | |
| 218 | size_of_stack_reserve: u32, | |
| 219 | size_of_stack_commit: u32, | |
| 220 | size_of_heap_reserve: u32, | |
| 221 | size_of_heap_commit: u32, | |
| 222 | loader_flags: u32, | |
| 223 | number_of_rva_and_sizes: u32, | |
| 224 | }; | |
| 192 | pub const Magic = enum(u16) { | |
| 193 | PE32 = 0x10b, | |
| 194 | @"PE32+" = 0x20b, | |
| 195 | _, | |
| 196 | }; | |
| 225 | 197 | |
| 226 | pub const OptionalHeaderPE64 = extern struct { | |
| 227 | magic: u16, | |
| 228 | major_linker_version: u8, | |
| 229 | minor_linker_version: u8, | |
| 230 | size_of_code: u32, | |
| 231 | size_of_initialized_data: u32, | |
| 232 | size_of_uninitialized_data: u32, | |
| 233 | address_of_entry_point: u32, | |
| 234 | base_of_code: u32, | |
| 235 | image_base: u64, | |
| 236 | section_alignment: u32, | |
| 237 | file_alignment: u32, | |
| 238 | major_operating_system_version: u16, | |
| 239 | minor_operating_system_version: u16, | |
| 240 | major_image_version: u16, | |
| 241 | minor_image_version: u16, | |
| 242 | major_subsystem_version: u16, | |
| 243 | minor_subsystem_version: u16, | |
| 244 | win32_version_value: u32, | |
| 245 | size_of_image: u32, | |
| 246 | size_of_headers: u32, | |
| 247 | checksum: u32, | |
| 248 | subsystem: Subsystem, | |
| 249 | dll_flags: DllFlags, | |
| 250 | size_of_stack_reserve: u64, | |
| 251 | size_of_stack_commit: u64, | |
| 252 | size_of_heap_reserve: u64, | |
| 253 | size_of_heap_commit: u64, | |
| 254 | loader_flags: u32, | |
| 255 | number_of_rva_and_sizes: u32, | |
| 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 | }; | |
| 256 | 248 | }; |
| 257 | 249 | |
| 258 | 250 | pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; |
| ... | ... | @@ -319,7 +311,7 @@ pub const BaseRelocationDirectoryEntry = extern struct { |
| 319 | 311 | block_size: u32, |
| 320 | 312 | }; |
| 321 | 313 | |
| 322 | pub const BaseRelocation = packed struct { | |
| 314 | pub const BaseRelocation = packed struct(u16) { | |
| 323 | 315 | /// 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. |
| 324 | 316 | /// This offset specifies where the base relocation is to be applied. |
| 325 | 317 | offset: u12, |
| ... | ... | @@ -447,12 +439,12 @@ pub const ImportDirectoryEntry = extern struct { |
| 447 | 439 | }; |
| 448 | 440 | |
| 449 | 441 | pub const ImportLookupEntry32 = struct { |
| 450 | pub const ByName = packed struct { | |
| 442 | pub const ByName = packed struct(u32) { | |
| 451 | 443 | name_table_rva: u31, |
| 452 | 444 | flag: u1 = 0, |
| 453 | 445 | }; |
| 454 | 446 | |
| 455 | pub const ByOrdinal = packed struct { | |
| 447 | pub const ByOrdinal = packed struct(u32) { | |
| 456 | 448 | ordinal_number: u16, |
| 457 | 449 | unused: u15 = 0, |
| 458 | 450 | flag: u1 = 1, |
| ... | ... | @@ -472,13 +464,13 @@ pub const ImportLookupEntry32 = struct { |
| 472 | 464 | }; |
| 473 | 465 | |
| 474 | 466 | pub const ImportLookupEntry64 = struct { |
| 475 | pub const ByName = packed struct { | |
| 467 | pub const ByName = packed struct(u64) { | |
| 476 | 468 | name_table_rva: u31, |
| 477 | 469 | unused: u32 = 0, |
| 478 | 470 | flag: u1 = 0, |
| 479 | 471 | }; |
| 480 | 472 | |
| 481 | pub const ByOrdinal = packed struct { | |
| 473 | pub const ByOrdinal = packed struct(u64) { | |
| 482 | 474 | ordinal_number: u16, |
| 483 | 475 | unused: u47 = 0, |
| 484 | 476 | flag: u1 = 1, |
| ... | ... | @@ -519,7 +511,7 @@ pub const SectionHeader = extern struct { |
| 519 | 511 | pointer_to_linenumbers: u32, |
| 520 | 512 | number_of_relocations: u16, |
| 521 | 513 | number_of_linenumbers: u16, |
| 522 | flags: SectionHeaderFlags, | |
| 514 | flags: SectionHeader.Flags, | |
| 523 | 515 | |
| 524 | 516 | pub fn getName(self: *align(1) const SectionHeader) ?[]const u8 { |
| 525 | 517 | if (self.name[0] == '/') return null; |
| ... | ... | @@ -546,109 +538,121 @@ pub const SectionHeader = extern struct { |
| 546 | 538 | } |
| 547 | 539 | |
| 548 | 540 | pub fn isCode(self: SectionHeader) bool { |
| 549 | return self.flags.CNT_CODE == 0b1; | |
| 541 | return self.flags.CNT_CODE; | |
| 550 | 542 | } |
| 551 | 543 | |
| 552 | 544 | pub fn isComdat(self: SectionHeader) bool { |
| 553 | return self.flags.LNK_COMDAT == 0b1; | |
| 545 | return self.flags.LNK_COMDAT; | |
| 554 | 546 | } |
| 555 | }; | |
| 556 | 547 | |
| 557 | pub const SectionHeaderFlags = packed struct { | |
| 558 | _reserved_0: u3 = 0, | |
| 548 | pub const Flags = packed struct(u32) { | |
| 549 | SCALE_INDEX: bool = false, | |
| 550 | ||
| 551 | unused1: u2 = 0, | |
| 559 | 552 | |
| 560 | /// The section should not be padded to the next boundary. | |
| 561 | /// This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. | |
| 562 | /// This is valid only for object files. | |
| 563 | TYPE_NO_PAD: u1 = 0, | |
| 553 | /// The section should not be padded to the next boundary. | |
| 554 | /// This flag is obsolete and is replaced by `.ALIGN = .@"1BYTES"`. | |
| 555 | /// This is valid only for object files. | |
| 556 | TYPE_NO_PAD: bool = false, | |
| 564 | 557 | |
| 565 | _reserved_1: u1 = 0, | |
| 558 | unused4: u1 = 0, | |
| 566 | 559 | |
| 567 | /// The section contains executable code. | |
| 568 | CNT_CODE: u1 = 0, | |
| 560 | /// The section contains executable code. | |
| 561 | CNT_CODE: bool = false, | |
| 569 | 562 | |
| 570 | /// The section contains initialized data. | |
| 571 | CNT_INITIALIZED_DATA: u1 = 0, | |
| 563 | /// The section contains initialized data. | |
| 564 | CNT_INITIALIZED_DATA: bool = false, | |
| 572 | 565 | |
| 573 | /// The section contains uninitialized data. | |
| 574 | CNT_UNINITIALIZED_DATA: u1 = 0, | |
| 566 | /// The section contains uninitialized data. | |
| 567 | CNT_UNINITIALIZED_DATA: bool = false, | |
| 575 | 568 | |
| 576 | /// Reserved for future use. | |
| 577 | LNK_OTHER: u1 = 0, | |
| 569 | /// Reserved for future use. | |
| 570 | LNK_OTHER: bool = false, | |
| 578 | 571 | |
| 579 | /// The section contains comments or other information. | |
| 580 | /// The .drectve section has this type. | |
| 581 | /// This is valid for object files only. | |
| 582 | LNK_INFO: u1 = 0, | |
| 572 | /// The section contains comments or other information. | |
| 573 | /// The .drectve section has this type. | |
| 574 | /// This is valid for object files only. | |
| 575 | LNK_INFO: bool = false, | |
| 583 | 576 | |
| 584 | _reserved_2: u1 = 0, | |
| 577 | unused10: u1 = 0, | |
| 585 | 578 | |
| 586 | /// The section will not become part of the image. | |
| 587 | /// This is valid only for object files. | |
| 588 | LNK_REMOVE: u1 = 0, | |
| 579 | /// The section will not become part of the image. | |
| 580 | /// This is valid only for object files. | |
| 581 | LNK_REMOVE: bool = false, | |
| 589 | 582 | |
| 590 | /// The section contains COMDAT data. | |
| 591 | /// For more information, see COMDAT Sections (Object Only). | |
| 592 | /// This is valid only for object files. | |
| 593 | LNK_COMDAT: u1 = 0, | |
| 583 | /// The section contains COMDAT data. | |
| 584 | /// For more information, see COMDAT Sections (Object Only). | |
| 585 | /// This is valid only for object files. | |
| 586 | LNK_COMDAT: bool = false, | |
| 594 | 587 | |
| 595 | _reserved_3: u2 = 0, | |
| 588 | unused13: u2 = 0, | |
| 596 | 589 | |
| 597 | /// The section contains data referenced through the global pointer (GP). | |
| 598 | GPREL: u1 = 0, | |
| 590 | union14: packed union { | |
| 591 | mask: u1, | |
| 592 | /// The section contains data referenced through the global pointer (GP). | |
| 593 | GPREL: bool, | |
| 594 | MEM_FARDATA: bool, | |
| 595 | } = .{ .mask = 0 }, | |
| 599 | 596 | |
| 600 | /// Reserved for future use. | |
| 601 | MEM_PURGEABLE: u1 = 0, | |
| 597 | unused15: u1 = 0, | |
| 602 | 598 | |
| 603 | /// Reserved for future use. | |
| 604 | MEM_16BIT: u1 = 0, | |
| 599 | union16: packed union { | |
| 600 | mask: u1, | |
| 601 | MEM_PURGEABLE: bool, | |
| 602 | MEM_16BIT: bool, | |
| 603 | } = .{ .mask = 0 }, | |
| 605 | 604 | |
| 606 | /// Reserved for future use. | |
| 607 | MEM_LOCKED: u1 = 0, | |
| 605 | /// Reserved for future use. | |
| 606 | MEM_LOCKED: bool = false, | |
| 608 | 607 | |
| 609 | /// Reserved for future use. | |
| 610 | MEM_PRELOAD: u1 = 0, | |
| 608 | /// Reserved for future use. | |
| 609 | MEM_PRELOAD: bool = false, | |
| 611 | 610 | |
| 612 | /// Takes on multiple values according to flags: | |
| 613 | /// pub const IMAGE_SCN_ALIGN_1BYTES: u32 = 0x100000; | |
| 614 | /// pub const IMAGE_SCN_ALIGN_2BYTES: u32 = 0x200000; | |
| 615 | /// pub const IMAGE_SCN_ALIGN_4BYTES: u32 = 0x300000; | |
| 616 | /// pub const IMAGE_SCN_ALIGN_8BYTES: u32 = 0x400000; | |
| 617 | /// pub const IMAGE_SCN_ALIGN_16BYTES: u32 = 0x500000; | |
| 618 | /// pub const IMAGE_SCN_ALIGN_32BYTES: u32 = 0x600000; | |
| 619 | /// pub const IMAGE_SCN_ALIGN_64BYTES: u32 = 0x700000; | |
| 620 | /// pub const IMAGE_SCN_ALIGN_128BYTES: u32 = 0x800000; | |
| 621 | /// pub const IMAGE_SCN_ALIGN_256BYTES: u32 = 0x900000; | |
| 622 | /// pub const IMAGE_SCN_ALIGN_512BYTES: u32 = 0xA00000; | |
| 623 | /// pub const IMAGE_SCN_ALIGN_1024BYTES: u32 = 0xB00000; | |
| 624 | /// pub const IMAGE_SCN_ALIGN_2048BYTES: u32 = 0xC00000; | |
| 625 | /// pub const IMAGE_SCN_ALIGN_4096BYTES: u32 = 0xD00000; | |
| 626 | /// pub const IMAGE_SCN_ALIGN_8192BYTES: u32 = 0xE00000; | |
| 627 | ALIGN: u4 = 0, | |
| 611 | ALIGN: SectionHeader.Flags.Align = .NONE, | |
| 628 | 612 | |
| 629 | /// The section contains extended relocations. | |
| 630 | LNK_NRELOC_OVFL: u1 = 0, | |
| 613 | /// The section contains extended relocations. | |
| 614 | LNK_NRELOC_OVFL: bool = false, | |
| 631 | 615 | |
| 632 | /// The section can be discarded as needed. | |
| 633 | MEM_DISCARDABLE: u1 = 0, | |
| 616 | /// The section can be discarded as needed. | |
| 617 | MEM_DISCARDABLE: bool = false, | |
| 634 | 618 | |
| 635 | /// The section cannot be cached. | |
| 636 | MEM_NOT_CACHED: u1 = 0, | |
| 619 | /// The section cannot be cached. | |
| 620 | MEM_NOT_CACHED: bool = false, | |
| 637 | 621 | |
| 638 | /// The section is not pageable. | |
| 639 | MEM_NOT_PAGED: u1 = 0, | |
| 622 | /// The section is not pageable. | |
| 623 | MEM_NOT_PAGED: bool = false, | |
| 640 | 624 | |
| 641 | /// The section can be shared in memory. | |
| 642 | MEM_SHARED: u1 = 0, | |
| 625 | /// The section can be shared in memory. | |
| 626 | MEM_SHARED: bool = false, | |
| 643 | 627 | |
| 644 | /// The section can be executed as code. | |
| 645 | MEM_EXECUTE: u1 = 0, | |
| 628 | /// The section can be executed as code. | |
| 629 | MEM_EXECUTE: bool = false, | |
| 646 | 630 | |
| 647 | /// The section can be read. | |
| 648 | MEM_READ: u1 = 0, | |
| 631 | /// The section can be read. | |
| 632 | MEM_READ: bool = false, | |
| 649 | 633 | |
| 650 | /// The section can be written to. | |
| 651 | MEM_WRITE: u1 = 0, | |
| 634 | /// The section can be written to. | |
| 635 | MEM_WRITE: bool = false, | |
| 636 | ||
| 637 | pub const Align = enum(u4) { | |
| 638 | NONE = 0, | |
| 639 | @"1BYTES" = 1, | |
| 640 | @"2BYTES" = 2, | |
| 641 | @"4BYTES" = 3, | |
| 642 | @"8BYTES" = 4, | |
| 643 | @"16BYTES" = 5, | |
| 644 | @"32BYTES" = 6, | |
| 645 | @"64BYTES" = 7, | |
| 646 | @"128BYTES" = 8, | |
| 647 | @"256BYTES" = 9, | |
| 648 | @"512BYTES" = 10, | |
| 649 | @"1024BYTES" = 11, | |
| 650 | @"2048BYTES" = 12, | |
| 651 | @"4096BYTES" = 13, | |
| 652 | @"8192BYTES" = 14, | |
| 653 | _, | |
| 654 | }; | |
| 655 | }; | |
| 652 | 656 | }; |
| 653 | 657 | |
| 654 | 658 | pub const Symbol = struct { |
| ... | ... | @@ -691,7 +695,7 @@ pub const SectionNumber = enum(u16) { |
| 691 | 695 | _, |
| 692 | 696 | }; |
| 693 | 697 | |
| 694 | pub const SymType = packed struct { | |
| 698 | pub const SymType = packed struct(u16) { | |
| 695 | 699 | complex_type: ComplexType, |
| 696 | 700 | base_type: BaseType, |
| 697 | 701 | }; |
| ... | ... | @@ -982,87 +986,7 @@ pub const DebugInfoDefinition = struct { |
| 982 | 986 | unused_3: [2]u8, |
| 983 | 987 | }; |
| 984 | 988 | |
| 985 | pub const MachineType = enum(u16) { | |
| 986 | UNKNOWN = 0x0, | |
| 987 | /// Alpha AXP, 32-bit address space | |
| 988 | ALPHA = 0x184, | |
| 989 | /// Alpha 64, 64-bit address space | |
| 990 | ALPHA64 = 0x284, | |
| 991 | /// Matsushita AM33 | |
| 992 | AM33 = 0x1d3, | |
| 993 | /// x64 | |
| 994 | X64 = 0x8664, | |
| 995 | /// ARM little endian | |
| 996 | ARM = 0x1c0, | |
| 997 | /// ARM64 little endian | |
| 998 | ARM64 = 0xaa64, | |
| 999 | /// ARM64EC | |
| 1000 | ARM64EC = 0xa641, | |
| 1001 | /// ARM64X | |
| 1002 | ARM64X = 0xa64e, | |
| 1003 | /// ARM Thumb-2 little endian | |
| 1004 | ARMNT = 0x1c4, | |
| 1005 | /// CEE | |
| 1006 | CEE = 0xc0ee, | |
| 1007 | /// CEF | |
| 1008 | CEF = 0xcef, | |
| 1009 | /// Hybrid PE | |
| 1010 | CHPE_X86 = 0x3a64, | |
| 1011 | /// EFI byte code | |
| 1012 | EBC = 0xebc, | |
| 1013 | /// Intel 386 or later processors and compatible processors | |
| 1014 | I386 = 0x14c, | |
| 1015 | /// Intel Itanium processor family | |
| 1016 | IA64 = 0x200, | |
| 1017 | /// LoongArch32 | |
| 1018 | LOONGARCH32 = 0x6232, | |
| 1019 | /// LoongArch64 | |
| 1020 | LOONGARCH64 = 0x6264, | |
| 1021 | /// Mitsubishi M32R little endian | |
| 1022 | M32R = 0x9041, | |
| 1023 | /// MIPS16 | |
| 1024 | MIPS16 = 0x266, | |
| 1025 | /// MIPS with FPU | |
| 1026 | MIPSFPU = 0x366, | |
| 1027 | /// MIPS16 with FPU | |
| 1028 | MIPSFPU16 = 0x466, | |
| 1029 | /// Power PC little endian | |
| 1030 | POWERPC = 0x1f0, | |
| 1031 | /// Power PC with floating point support | |
| 1032 | POWERPCFP = 0x1f1, | |
| 1033 | /// MIPS little endian | |
| 1034 | R3000 = 0x162, | |
| 1035 | /// MIPS little endian | |
| 1036 | R4000 = 0x166, | |
| 1037 | /// MIPS little endian | |
| 1038 | R10000 = 0x168, | |
| 1039 | /// RISC-V 32-bit address space | |
| 1040 | RISCV32 = 0x5032, | |
| 1041 | /// RISC-V 64-bit address space | |
| 1042 | RISCV64 = 0x5064, | |
| 1043 | /// RISC-V 128-bit address space | |
| 1044 | RISCV128 = 0x5128, | |
| 1045 | /// Hitachi SH3 | |
| 1046 | SH3 = 0x1a2, | |
| 1047 | /// Hitachi SH3 DSP | |
| 1048 | SH3DSP = 0x1a3, | |
| 1049 | /// SH3E little-endian | |
| 1050 | SH3E = 0x1a4, | |
| 1051 | /// Hitachi SH4 | |
| 1052 | SH4 = 0x1a6, | |
| 1053 | /// Hitachi SH5 | |
| 1054 | SH5 = 0x1a8, | |
| 1055 | /// Thumb | |
| 1056 | THUMB = 0x1c2, | |
| 1057 | /// Infineon | |
| 1058 | TRICORE = 0x520, | |
| 1059 | /// MIPS little-endian WCE v2 | |
| 1060 | WCEMIPSV2 = 0x169, | |
| 1061 | ||
| 1062 | _, | |
| 1063 | }; | |
| 1064 | ||
| 1065 | pub const CoffError = error{ | |
| 989 | pub const Error = error{ | |
| 1066 | 990 | InvalidPEMagic, |
| 1067 | 991 | InvalidPEHeader, |
| 1068 | 992 | InvalidMachine, |
| ... | ... | @@ -1104,7 +1028,7 @@ pub const Coff = struct { |
| 1104 | 1028 | |
| 1105 | 1029 | // Do some basic validation upfront |
| 1106 | 1030 | if (is_image) { |
| 1107 | const coff_header = coff.getCoffHeader(); | |
| 1031 | const coff_header = coff.getHeader(); | |
| 1108 | 1032 | if (coff_header.size_of_optional_header == 0) return error.MissingPEHeader; |
| 1109 | 1033 | } |
| 1110 | 1034 | |
| ... | ... | @@ -1161,31 +1085,31 @@ pub const Coff = struct { |
| 1161 | 1085 | return self.data[start .. start + len]; |
| 1162 | 1086 | } |
| 1163 | 1087 | |
| 1164 | pub fn getCoffHeader(self: Coff) CoffHeader { | |
| 1165 | return @as(*align(1) const CoffHeader, @ptrCast(self.data[self.coff_header_offset..][0..@sizeOf(CoffHeader)])).*; | |
| 1088 | pub fn getHeader(self: Coff) Header { | |
| 1089 | return @as(*align(1) const Header, @ptrCast(self.data[self.coff_header_offset..][0..@sizeOf(Header)])).*; | |
| 1166 | 1090 | } |
| 1167 | 1091 | |
| 1168 | 1092 | pub fn getOptionalHeader(self: Coff) OptionalHeader { |
| 1169 | 1093 | assert(self.is_image); |
| 1170 | const offset = self.coff_header_offset + @sizeOf(CoffHeader); | |
| 1094 | const offset = self.coff_header_offset + @sizeOf(Header); | |
| 1171 | 1095 | return @as(*align(1) const OptionalHeader, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader)])).*; |
| 1172 | 1096 | } |
| 1173 | 1097 | |
| 1174 | pub fn getOptionalHeader32(self: Coff) OptionalHeaderPE32 { | |
| 1098 | pub fn getOptionalHeader32(self: Coff) OptionalHeader.PE32 { | |
| 1175 | 1099 | assert(self.is_image); |
| 1176 | const offset = self.coff_header_offset + @sizeOf(CoffHeader); | |
| 1177 | return @as(*align(1) const OptionalHeaderPE32, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeaderPE32)])).*; | |
| 1100 | const offset = self.coff_header_offset + @sizeOf(Header); | |
| 1101 | return @as(*align(1) const OptionalHeader.PE32, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader.PE32)])).*; | |
| 1178 | 1102 | } |
| 1179 | 1103 | |
| 1180 | pub fn getOptionalHeader64(self: Coff) OptionalHeaderPE64 { | |
| 1104 | pub fn getOptionalHeader64(self: Coff) OptionalHeader.@"PE32+" { | |
| 1181 | 1105 | assert(self.is_image); |
| 1182 | const offset = self.coff_header_offset + @sizeOf(CoffHeader); | |
| 1183 | return @as(*align(1) const OptionalHeaderPE64, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeaderPE64)])).*; | |
| 1106 | const offset = self.coff_header_offset + @sizeOf(Header); | |
| 1107 | return @as(*align(1) const OptionalHeader.@"PE32+", @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader.@"PE32+")])).*; | |
| 1184 | 1108 | } |
| 1185 | 1109 | |
| 1186 | 1110 | pub fn getImageBase(self: Coff) u64 { |
| 1187 | 1111 | const hdr = self.getOptionalHeader(); |
| 1188 | return switch (hdr.magic) { | |
| 1112 | return switch (@intFromEnum(hdr.magic)) { | |
| 1189 | 1113 | IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().image_base, |
| 1190 | 1114 | IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().image_base, |
| 1191 | 1115 | else => unreachable, // We assume we have validated the header already |
| ... | ... | @@ -1194,7 +1118,7 @@ pub const Coff = struct { |
| 1194 | 1118 | |
| 1195 | 1119 | pub fn getNumberOfDataDirectories(self: Coff) u32 { |
| 1196 | 1120 | const hdr = self.getOptionalHeader(); |
| 1197 | return switch (hdr.magic) { | |
| 1121 | return switch (@intFromEnum(hdr.magic)) { | |
| 1198 | 1122 | IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().number_of_rva_and_sizes, |
| 1199 | 1123 | IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().number_of_rva_and_sizes, |
| 1200 | 1124 | else => unreachable, // We assume we have validated the header already |
| ... | ... | @@ -1203,17 +1127,17 @@ pub const Coff = struct { |
| 1203 | 1127 | |
| 1204 | 1128 | pub fn getDataDirectories(self: *const Coff) []align(1) const ImageDataDirectory { |
| 1205 | 1129 | const hdr = self.getOptionalHeader(); |
| 1206 | const size: usize = switch (hdr.magic) { | |
| 1207 | IMAGE_NT_OPTIONAL_HDR32_MAGIC => @sizeOf(OptionalHeaderPE32), | |
| 1208 | IMAGE_NT_OPTIONAL_HDR64_MAGIC => @sizeOf(OptionalHeaderPE64), | |
| 1130 | const size: usize = switch (@intFromEnum(hdr.magic)) { | |
| 1131 | IMAGE_NT_OPTIONAL_HDR32_MAGIC => @sizeOf(OptionalHeader.PE32), | |
| 1132 | IMAGE_NT_OPTIONAL_HDR64_MAGIC => @sizeOf(OptionalHeader.@"PE32+"), | |
| 1209 | 1133 | else => unreachable, // We assume we have validated the header already |
| 1210 | 1134 | }; |
| 1211 | const offset = self.coff_header_offset + @sizeOf(CoffHeader) + size; | |
| 1135 | const offset = self.coff_header_offset + @sizeOf(Header) + size; | |
| 1212 | 1136 | return @as([*]align(1) const ImageDataDirectory, @ptrCast(self.data[offset..]))[0..self.getNumberOfDataDirectories()]; |
| 1213 | 1137 | } |
| 1214 | 1138 | |
| 1215 | 1139 | pub fn getSymtab(self: *const Coff) ?Symtab { |
| 1216 | const coff_header = self.getCoffHeader(); | |
| 1140 | const coff_header = self.getHeader(); | |
| 1217 | 1141 | if (coff_header.pointer_to_symbol_table == 0) return null; |
| 1218 | 1142 | |
| 1219 | 1143 | const offset = coff_header.pointer_to_symbol_table; |
| ... | ... | @@ -1222,7 +1146,7 @@ pub const Coff = struct { |
| 1222 | 1146 | } |
| 1223 | 1147 | |
| 1224 | 1148 | pub fn getStrtab(self: *const Coff) error{InvalidStrtabSize}!?Strtab { |
| 1225 | const coff_header = self.getCoffHeader(); | |
| 1149 | const coff_header = self.getHeader(); | |
| 1226 | 1150 | if (coff_header.pointer_to_symbol_table == 0) return null; |
| 1227 | 1151 | |
| 1228 | 1152 | const offset = coff_header.pointer_to_symbol_table + Symbol.sizeOf() * coff_header.number_of_symbols; |
| ... | ... | @@ -1238,8 +1162,8 @@ pub const Coff = struct { |
| 1238 | 1162 | } |
| 1239 | 1163 | |
| 1240 | 1164 | pub fn getSectionHeaders(self: *const Coff) []align(1) const SectionHeader { |
| 1241 | const coff_header = self.getCoffHeader(); | |
| 1242 | const offset = self.coff_header_offset + @sizeOf(CoffHeader) + coff_header.size_of_optional_header; | |
| 1165 | const coff_header = self.getHeader(); | |
| 1166 | const offset = self.coff_header_offset + @sizeOf(Header) + coff_header.size_of_optional_header; | |
| 1243 | 1167 | return @as([*]align(1) const SectionHeader, @ptrCast(self.data.ptr + offset))[0..coff_header.number_of_sections]; |
| 1244 | 1168 | } |
| 1245 | 1169 | |
| ... | ... | @@ -1414,14 +1338,14 @@ pub const Strtab = struct { |
| 1414 | 1338 | }; |
| 1415 | 1339 | |
| 1416 | 1340 | pub const ImportHeader = extern struct { |
| 1417 | sig1: MachineType, | |
| 1341 | sig1: IMAGE.FILE.MACHINE, | |
| 1418 | 1342 | sig2: u16, |
| 1419 | 1343 | version: u16, |
| 1420 | machine: MachineType, | |
| 1344 | machine: IMAGE.FILE.MACHINE, | |
| 1421 | 1345 | time_date_stamp: u32, |
| 1422 | 1346 | size_of_data: u32, |
| 1423 | 1347 | hint: u16, |
| 1424 | types: packed struct { | |
| 1348 | types: packed struct(u32) { | |
| 1425 | 1349 | type: ImportType, |
| 1426 | 1350 | name_type: ImportNameType, |
| 1427 | 1351 | reserved: u11, |
| ... | ... | @@ -1461,119 +1385,534 @@ pub const Relocation = extern struct { |
| 1461 | 1385 | type: u16, |
| 1462 | 1386 | }; |
| 1463 | 1387 | |
| 1464 | pub const ImageRelAmd64 = enum(u16) { | |
| 1465 | /// The relocation is ignored. | |
| 1466 | absolute = 0, | |
| 1467 | ||
| 1468 | /// The 64-bit VA of the relocation target. | |
| 1469 | addr64 = 1, | |
| 1470 | ||
| 1471 | /// The 32-bit VA of the relocation target. | |
| 1472 | addr32 = 2, | |
| 1473 | ||
| 1474 | /// The 32-bit address without an image base. | |
| 1475 | addr32nb = 3, | |
| 1476 | ||
| 1477 | /// The 32-bit relative address from the byte following the relocation. | |
| 1478 | rel32 = 4, | |
| 1479 | ||
| 1480 | /// The 32-bit address relative to byte distance 1 from the relocation. | |
| 1481 | rel32_1 = 5, | |
| 1482 | ||
| 1483 | /// The 32-bit address relative to byte distance 2 from the relocation. | |
| 1484 | rel32_2 = 6, | |
| 1485 | ||
| 1486 | /// The 32-bit address relative to byte distance 3 from the relocation. | |
| 1487 | rel32_3 = 7, | |
| 1488 | ||
| 1489 | /// The 32-bit address relative to byte distance 4 from the relocation. | |
| 1490 | rel32_4 = 8, | |
| 1491 | ||
| 1492 | /// The 32-bit address relative to byte distance 5 from the relocation. | |
| 1493 | rel32_5 = 9, | |
| 1494 | ||
| 1495 | /// The 16-bit section index of the section that contains the target. | |
| 1496 | /// This is used to support debugging information. | |
| 1497 | section = 10, | |
| 1498 | ||
| 1499 | /// The 32-bit offset of the target from the beginning of its section. | |
| 1500 | /// This is used to support debugging information and static thread local storage. | |
| 1501 | secrel = 11, | |
| 1502 | ||
| 1503 | /// A 7-bit unsigned offset from the base of the section that contains the target. | |
| 1504 | secrel7 = 12, | |
| 1505 | ||
| 1506 | /// CLR tokens. | |
| 1507 | token = 13, | |
| 1508 | ||
| 1509 | /// A 32-bit signed span-dependent value emitted into the object. | |
| 1510 | srel32 = 14, | |
| 1511 | ||
| 1512 | /// A pair that must immediately follow every span-dependent value. | |
| 1513 | pair = 15, | |
| 1514 | ||
| 1515 | /// A 32-bit signed span-dependent value that is applied at link time. | |
| 1516 | sspan32 = 16, | |
| 1517 | ||
| 1518 | _, | |
| 1519 | }; | |
| 1520 | ||
| 1521 | pub const ImageRelArm64 = enum(u16) { | |
| 1522 | /// The relocation is ignored. | |
| 1523 | absolute = 0, | |
| 1524 | ||
| 1525 | /// The 32-bit VA of the target. | |
| 1526 | addr32 = 1, | |
| 1527 | ||
| 1528 | /// The 32-bit RVA of the target. | |
| 1529 | addr32nb = 2, | |
| 1530 | ||
| 1531 | /// The 26-bit relative displacement to the target, for B and BL instructions. | |
| 1532 | branch26 = 3, | |
| 1533 | ||
| 1534 | /// The page base of the target, for ADRP instruction. | |
| 1535 | pagebase_rel21 = 4, | |
| 1536 | ||
| 1537 | /// The 21-bit relative displacement to the target, for instruction ADR. | |
| 1538 | rel21 = 5, | |
| 1539 | ||
| 1540 | /// The 12-bit page offset of the target, for instructions ADD/ADDS (immediate) with zero shift. | |
| 1541 | pageoffset_12a = 6, | |
| 1542 | ||
| 1543 | /// The 12-bit page offset of the target, for instruction LDR (indexed, unsigned immediate). | |
| 1544 | pageoffset_12l = 7, | |
| 1545 | ||
| 1546 | /// The 32-bit offset of the target from the beginning of its section. | |
| 1547 | /// This is used to support debugging information and static thread local storage. | |
| 1548 | secrel = 8, | |
| 1549 | ||
| 1550 | /// Bit 0:11 of section offset of the target for instructions ADD/ADDS (immediate) with zero shift. | |
| 1551 | low12a = 9, | |
| 1388 | pub const IMAGE = struct { | |
| 1389 | pub const FILE = struct { | |
| 1390 | /// Machine Types | |
| 1391 | /// The Machine field has one of the following values, which specify the CPU type. | |
| 1392 | /// An image file can be run only on the specified machine or on a system that emulates the specified machine. | |
| 1393 | pub const MACHINE = enum(u16) { | |
| 1394 | /// The content of this field is assumed to be applicable to any machine type | |
| 1395 | UNKNOWN = 0x0, | |
| 1396 | /// Alpha AXP, 32-bit address space | |
| 1397 | ALPHA = 0x184, | |
| 1398 | /// Alpha 64, 64-bit address space | |
| 1399 | ALPHA64 = 0x284, | |
| 1400 | /// Matsushita AM33 | |
| 1401 | AM33 = 0x1d3, | |
| 1402 | /// x64 | |
| 1403 | AMD64 = 0x8664, | |
| 1404 | /// ARM little endian | |
| 1405 | ARM = 0x1c0, | |
| 1406 | /// ARM64 little endian | |
| 1407 | ARM64 = 0xaa64, | |
| 1408 | /// ABI that enables interoperability between native ARM64 and emulated x64 code. | |
| 1409 | ARM64EC = 0xA641, | |
| 1410 | /// Binary format that allows both native ARM64 and ARM64EC code to coexist in the same file. | |
| 1411 | ARM64X = 0xA64E, | |
| 1412 | /// ARM Thumb-2 little endian | |
| 1413 | ARMNT = 0x1c4, | |
| 1414 | /// EFI byte code | |
| 1415 | EBC = 0xebc, | |
| 1416 | /// Intel 386 or later processors and compatible processors | |
| 1417 | I386 = 0x14c, | |
| 1418 | /// Intel Itanium processor family | |
| 1419 | IA64 = 0x200, | |
| 1420 | /// LoongArch 32-bit processor family | |
| 1421 | LOONGARCH32 = 0x6232, | |
| 1422 | /// LoongArch 64-bit processor family | |
| 1423 | LOONGARCH64 = 0x6264, | |
| 1424 | /// Mitsubishi M32R little endian | |
| 1425 | M32R = 0x9041, | |
| 1426 | /// MIPS16 | |
| 1427 | MIPS16 = 0x266, | |
| 1428 | /// MIPS with FPU | |
| 1429 | MIPSFPU = 0x366, | |
| 1430 | /// MIPS16 with FPU | |
| 1431 | MIPSFPU16 = 0x466, | |
| 1432 | /// Power PC little endian | |
| 1433 | POWERPC = 0x1f0, | |
| 1434 | /// Power PC with floating point support | |
| 1435 | POWERPCFP = 0x1f1, | |
| 1436 | /// MIPS I compatible 32-bit big endian | |
| 1437 | R3000BE = 0x160, | |
| 1438 | /// MIPS I compatible 32-bit little endian | |
| 1439 | R3000 = 0x162, | |
| 1440 | /// MIPS III compatible 64-bit little endian | |
| 1441 | R4000 = 0x166, | |
| 1442 | /// MIPS IV compatible 64-bit little endian | |
| 1443 | R10000 = 0x168, | |
| 1444 | /// RISC-V 32-bit address space | |
| 1445 | RISCV32 = 0x5032, | |
| 1446 | /// RISC-V 64-bit address space | |
| 1447 | RISCV64 = 0x5064, | |
| 1448 | /// RISC-V 128-bit address space | |
| 1449 | RISCV128 = 0x5128, | |
| 1450 | /// Hitachi SH3 | |
| 1451 | SH3 = 0x1a2, | |
| 1452 | /// Hitachi SH3 DSP | |
| 1453 | SH3DSP = 0x1a3, | |
| 1454 | /// Hitachi SH4 | |
| 1455 | SH4 = 0x1a6, | |
| 1456 | /// Hitachi SH5 | |
| 1457 | SH5 = 0x1a8, | |
| 1458 | /// Thumb | |
| 1459 | THUMB = 0x1c2, | |
| 1460 | /// MIPS little-endian WCE v2 | |
| 1461 | WCEMIPSV2 = 0x169, | |
| 1462 | _, | |
| 1463 | /// AXP 64 (Same as Alpha 64) | |
| 1464 | pub const AXP64: IMAGE.FILE.MACHINE = .ALPHA64; | |
| 1465 | }; | |
| 1466 | }; | |
| 1552 | 1467 | |
| 1553 | /// Bit 12:23 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift. | |
| 1554 | high12a = 10, | |
| 1468 | pub const REL = struct { | |
| 1469 | /// x64 Processors | |
| 1470 | /// The following relocation type indicators are defined for x64 and compatible processors. | |
| 1471 | pub const AMD64 = enum(u16) { | |
| 1472 | /// The relocation is ignored. | |
| 1473 | ABSOLUTE = 0x0000, | |
| 1474 | /// The 64-bit VA of the relocation target. | |
| 1475 | ADDR64 = 0x0001, | |
| 1476 | /// The 32-bit VA of the relocation target. | |
| 1477 | ADDR32 = 0x0002, | |
| 1478 | /// The 32-bit address without an image base (RVA). | |
| 1479 | ADDR32NB = 0x0003, | |
| 1480 | /// The 32-bit relative address from the byte following the relocation. | |
| 1481 | REL32 = 0x0004, | |
| 1482 | /// The 32-bit address relative to byte distance 1 from the relocation. | |
| 1483 | REL32_1 = 0x0005, | |
| 1484 | /// The 32-bit address relative to byte distance 2 from the relocation. | |
| 1485 | REL32_2 = 0x0006, | |
| 1486 | /// The 32-bit address relative to byte distance 3 from the relocation. | |
| 1487 | REL32_3 = 0x0007, | |
| 1488 | /// The 32-bit address relative to byte distance 4 from the relocation. | |
| 1489 | REL32_4 = 0x0008, | |
| 1490 | /// The 32-bit address relative to byte distance 5 from the relocation. | |
| 1491 | REL32_5 = 0x0009, | |
| 1492 | /// The 16-bit section index of the section that contains the target. | |
| 1493 | /// This is used to support debugging information. | |
| 1494 | SECTION = 0x000A, | |
| 1495 | /// The 32-bit offset of the target from the beginning of its section. | |
| 1496 | /// This is used to support debugging information and static thread local storage. | |
| 1497 | SECREL = 0x000B, | |
| 1498 | /// A 7-bit unsigned offset from the base of the section that contains the target. | |
| 1499 | SECREL7 = 0x000C, | |
| 1500 | /// CLR tokens. | |
| 1501 | TOKEN = 0x000D, | |
| 1502 | /// A 32-bit signed span-dependent value emitted into the object. | |
| 1503 | SREL32 = 0x000E, | |
| 1504 | /// A pair that must immediately follow every span-dependent value. | |
| 1505 | PAIR = 0x000F, | |
| 1506 | /// A 32-bit signed span-dependent value that is applied at link time. | |
| 1507 | SSPAN32 = 0x0010, | |
| 1508 | _, | |
| 1509 | }; | |
| 1555 | 1510 | |
| 1556 | /// Bit 0:11 of section offset of the target, for instruction LDR (indexed, unsigned immediate). | |
| 1557 | low12l = 11, | |
| 1511 | /// ARM Processors | |
| 1512 | /// The following relocation type indicators are defined for ARM processors. | |
| 1513 | pub const ARM = enum(u16) { | |
| 1514 | /// The relocation is ignored. | |
| 1515 | ABSOLUTE = 0x0000, | |
| 1516 | /// The 32-bit VA of the target. | |
| 1517 | ADDR32 = 0x0001, | |
| 1518 | /// The 32-bit RVA of the target. | |
| 1519 | ADDR32NB = 0x0002, | |
| 1520 | /// The 24-bit relative displacement to the target. | |
| 1521 | BRANCH24 = 0x0003, | |
| 1522 | /// The reference to a subroutine call. | |
| 1523 | /// The reference consists of two 16-bit instructions with 11-bit offsets. | |
| 1524 | BRANCH11 = 0x0004, | |
| 1525 | /// The 32-bit relative address from the byte following the relocation. | |
| 1526 | REL32 = 0x000A, | |
| 1527 | /// The 16-bit section index of the section that contains the target. | |
| 1528 | /// This is used to support debugging information. | |
| 1529 | SECTION = 0x000E, | |
| 1530 | /// The 32-bit offset of the target from the beginning of its section. | |
| 1531 | /// This is used to support debugging information and static thread local storage. | |
| 1532 | SECREL = 0x000F, | |
| 1533 | /// The 32-bit VA of the target. | |
| 1534 | /// This relocation is applied using a MOVW instruction for the low 16 bits followed by a MOVT for the high 16 bits. | |
| 1535 | MOV32 = 0x0010, | |
| 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 | THUMB_MOV32 = 0x0011, | |
| 1539 | /// The instruction is fixed up with the 21-bit relative displacement to the 2-byte aligned target. | |
| 1540 | /// The least significant bit of the displacement is always zero and is not stored. | |
| 1541 | /// This relocation corresponds to a Thumb-2 32-bit conditional B instruction. | |
| 1542 | THUMB_BRANCH20 = 0x0012, | |
| 1543 | Unused = 0x0013, | |
| 1544 | /// The instruction is fixed up with the 25-bit relative displacement to the 2-byte aligned target. | |
| 1545 | /// The least significant bit of the displacement is zero and is not stored.This relocation corresponds to a Thumb-2 B instruction. | |
| 1546 | THUMB_BRANCH24 = 0x0014, | |
| 1547 | /// The instruction is fixed up with the 25-bit relative displacement to the 4-byte aligned target. | |
| 1548 | /// The low 2 bits of the displacement are zero and are not stored. | |
| 1549 | /// This relocation corresponds to a Thumb-2 BLX instruction. | |
| 1550 | THUMB_BLX23 = 0x0015, | |
| 1551 | /// The relocation is valid only when it immediately follows a ARM_REFHI or THUMB_REFHI. | |
| 1552 | /// Its SymbolTableIndex contains a displacement and not an index into the symbol table. | |
| 1553 | PAIR = 0x0016, | |
| 1554 | _, | |
| 1555 | }; | |
| 1558 | 1556 | |
| 1559 | /// CLR token. | |
| 1560 | token = 12, | |
| 1557 | /// ARM64 Processors | |
| 1558 | /// The following relocation type indicators are defined for ARM64 processors. | |
| 1559 | pub const ARM64 = enum(u16) { | |
| 1560 | /// The relocation is ignored. | |
| 1561 | ABSOLUTE = 0x0000, | |
| 1562 | /// The 32-bit VA of the target. | |
| 1563 | ADDR32 = 0x0001, | |
| 1564 | /// The 32-bit RVA of the target. | |
| 1565 | ADDR32NB = 0x0002, | |
| 1566 | /// The 26-bit relative displacement to the target, for B and BL instructions. | |
| 1567 | BRANCH26 = 0x0003, | |
| 1568 | /// The page base of the target, for ADRP instruction. | |
| 1569 | PAGEBASE_REL21 = 0x0004, | |
| 1570 | /// The 12-bit relative displacement to the target, for instruction ADR | |
| 1571 | REL21 = 0x0005, | |
| 1572 | /// The 12-bit page offset of the target, for instructions ADD/ADDS (immediate) with zero shift. | |
| 1573 | PAGEOFFSET_12A = 0x0006, | |
| 1574 | /// The 12-bit page offset of the target, for instruction LDR (indexed, unsigned immediate). | |
| 1575 | PAGEOFFSET_12L = 0x0007, | |
| 1576 | /// The 32-bit offset of the target from the beginning of its section. | |
| 1577 | /// This is used to support debugging information and static thread local storage. | |
| 1578 | SECREL = 0x0008, | |
| 1579 | /// Bit 0:11 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift. | |
| 1580 | SECREL_LOW12A = 0x0009, | |
| 1581 | /// Bit 12:23 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift. | |
| 1582 | SECREL_HIGH12A = 0x000A, | |
| 1583 | /// Bit 0:11 of section offset of the target, for instruction LDR (indexed, unsigned immediate). | |
| 1584 | SECREL_LOW12L = 0x000B, | |
| 1585 | /// CLR token. | |
| 1586 | TOKEN = 0x000C, | |
| 1587 | /// The 16-bit section index of the section that contains the target. | |
| 1588 | /// This is used to support debugging information. | |
| 1589 | SECTION = 0x000D, | |
| 1590 | /// The 64-bit VA of the relocation target. | |
| 1591 | ADDR64 = 0x000E, | |
| 1592 | /// The 19-bit offset to the relocation target, for conditional B instruction. | |
| 1593 | BRANCH19 = 0x000F, | |
| 1594 | /// The 14-bit offset to the relocation target, for instructions TBZ and TBNZ. | |
| 1595 | BRANCH14 = 0x0010, | |
| 1596 | /// The 32-bit relative address from the byte following the relocation. | |
| 1597 | REL32 = 0x0011, | |
| 1598 | _, | |
| 1599 | }; | |
| 1561 | 1600 | |
| 1562 | /// The 16-bit section index of the section that contains the target. | |
| 1563 | /// This is used to support debugging information. | |
| 1564 | section = 13, | |
| 1601 | /// Hitachi SuperH Processors | |
| 1602 | /// The following relocation type indicators are defined for SH3 and SH4 processors. | |
| 1603 | /// SH5-specific relocations are noted as SHM (SH Media). | |
| 1604 | pub const SH = enum(u16) { | |
| 1605 | /// The relocation is ignored. | |
| 1606 | @"3_ABSOLUTE" = 0x0000, | |
| 1607 | /// A reference to the 16-bit location that contains the VA of the target symbol. | |
| 1608 | @"3_DIRECT16" = 0x0001, | |
| 1609 | /// The 32-bit VA of the target symbol. | |
| 1610 | @"3_DIRECT32" = 0x0002, | |
| 1611 | /// A reference to the 8-bit location that contains the VA of the target symbol. | |
| 1612 | @"3_DIRECT8" = 0x0003, | |
| 1613 | /// A reference to the 8-bit instruction that contains the effective 16-bit VA of the target symbol. | |
| 1614 | @"3_DIRECT8_WORD" = 0x0004, | |
| 1615 | /// A reference to the 8-bit instruction that contains the effective 32-bit VA of the target symbol. | |
| 1616 | @"3_DIRECT8_LONG" = 0x0005, | |
| 1617 | /// A reference to the 8-bit location whose low 4 bits contain the VA of the target symbol. | |
| 1618 | @"3_DIRECT4" = 0x0006, | |
| 1619 | /// A reference to the 8-bit instruction whose low 4 bits contain the effective 16-bit VA of the target symbol. | |
| 1620 | @"3_DIRECT4_WORD" = 0x0007, | |
| 1621 | /// A reference to the 8-bit instruction whose low 4 bits contain the effective 32-bit VA of the target symbol. | |
| 1622 | @"3_DIRECT4_LONG" = 0x0008, | |
| 1623 | /// A reference to the 8-bit instruction that contains the effective 16-bit relative offset of the target symbol. | |
| 1624 | @"3_PCREL8_WORD" = 0x0009, | |
| 1625 | /// A reference to the 8-bit instruction that contains the effective 32-bit relative offset of the target symbol. | |
| 1626 | @"3_PCREL8_LONG" = 0x000A, | |
| 1627 | /// A reference to the 16-bit instruction whose low 12 bits contain the effective 16-bit relative offset of the target symbol. | |
| 1628 | @"3_PCREL12_WORD" = 0x000B, | |
| 1629 | /// A reference to a 32-bit location that is the VA of the section that contains the target symbol. | |
| 1630 | @"3_STARTOF_SECTION" = 0x000C, | |
| 1631 | /// A reference to the 32-bit location that is the size of the section that contains the target symbol. | |
| 1632 | @"3_SIZEOF_SECTION" = 0x000D, | |
| 1633 | /// The 16-bit section index of the section that contains the target. | |
| 1634 | /// This is used to support debugging information. | |
| 1635 | @"3_SECTION" = 0x000E, | |
| 1636 | /// The 32-bit offset of the target from the beginning of its section. | |
| 1637 | /// This is used to support debugging information and static thread local storage. | |
| 1638 | @"3_SECREL" = 0x000F, | |
| 1639 | /// The 32-bit RVA of the target symbol. | |
| 1640 | @"3_DIRECT32_NB" = 0x0010, | |
| 1641 | /// GP relative. | |
| 1642 | @"3_GPREL4_LONG" = 0x0011, | |
| 1643 | /// CLR token. | |
| 1644 | @"3_TOKEN" = 0x0012, | |
| 1645 | /// The offset from the current instruction in longwords. | |
| 1646 | /// If the NOMODE bit is not set, insert the inverse of the low bit at bit 32 to select PTA or PTB. | |
| 1647 | M_PCRELPT = 0x0013, | |
| 1648 | /// The low 16 bits of the 32-bit address. | |
| 1649 | M_REFLO = 0x0014, | |
| 1650 | /// The high 16 bits of the 32-bit address. | |
| 1651 | M_REFHALF = 0x0015, | |
| 1652 | /// The low 16 bits of the relative address. | |
| 1653 | M_RELLO = 0x0016, | |
| 1654 | /// The high 16 bits of the relative address. | |
| 1655 | M_RELHALF = 0x0017, | |
| 1656 | /// The relocation is valid only when it immediately follows a REFHALF, RELHALF, or RELLO relocation. | |
| 1657 | /// The SymbolTableIndex field of the relocation contains a displacement and not an index into the symbol table. | |
| 1658 | M_PAIR = 0x0018, | |
| 1659 | /// The relocation ignores section mode. | |
| 1660 | M_NOMODE = 0x8000, | |
| 1661 | _, | |
| 1662 | }; | |
| 1565 | 1663 | |
| 1566 | /// The 64-bit VA of the relocation target. | |
| 1567 | addr64 = 14, | |
| 1664 | /// IBM PowerPC Processors | |
| 1665 | /// The following relocation type indicators are defined for PowerPC processors. | |
| 1666 | pub const PPC = enum(u16) { | |
| 1667 | /// The relocation is ignored. | |
| 1668 | ABSOLUTE = 0x0000, | |
| 1669 | /// The 64-bit VA of the target. | |
| 1670 | ADDR64 = 0x0001, | |
| 1671 | /// The 32-bit VA of the target. | |
| 1672 | ADDR32 = 0x0002, | |
| 1673 | /// The low 24 bits of the VA of the target. | |
| 1674 | /// This is valid only when the target symbol is absolute and can be sign-extended to its original value. | |
| 1675 | ADDR24 = 0x0003, | |
| 1676 | /// The low 16 bits of the target's VA. | |
| 1677 | ADDR16 = 0x0004, | |
| 1678 | /// The low 14 bits of the target's VA. | |
| 1679 | /// This is valid only when the target symbol is absolute and can be sign-extended to its original value. | |
| 1680 | ADDR14 = 0x0005, | |
| 1681 | /// A 24-bit PC-relative offset to the symbol's location. | |
| 1682 | REL24 = 0x0006, | |
| 1683 | /// A 14-bit PC-relative offset to the symbol's location. | |
| 1684 | REL14 = 0x0007, | |
| 1685 | /// The 32-bit RVA of the target. | |
| 1686 | ADDR32NB = 0x000A, | |
| 1687 | /// The 32-bit offset of the target from the beginning of its section. | |
| 1688 | /// This is used to support debugging information and static thread local storage. | |
| 1689 | SECREL = 0x000B, | |
| 1690 | /// The 16-bit section index of the section that contains the target. | |
| 1691 | /// This is used to support debugging information. | |
| 1692 | SECTION = 0x000C, | |
| 1693 | /// The 16-bit offset of the target from the beginning of its section. | |
| 1694 | /// This is used to support debugging information and static thread local storage. | |
| 1695 | SECREL16 = 0x000F, | |
| 1696 | /// The high 16 bits of the target's 32-bit VA. | |
| 1697 | /// This is used for the first instruction in a two-instruction sequence that loads a full address. | |
| 1698 | /// 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. | |
| 1699 | REFHI = 0x0010, | |
| 1700 | /// The low 16 bits of the target's VA. | |
| 1701 | REFLO = 0x0011, | |
| 1702 | /// A relocation that is valid only when it immediately follows a REFHI or SECRELHI relocation. | |
| 1703 | /// Its SymbolTableIndex contains a displacement and not an index into the symbol table. | |
| 1704 | PAIR = 0x0012, | |
| 1705 | /// The low 16 bits of the 32-bit offset of the target from the beginning of its section. | |
| 1706 | SECRELLO = 0x0013, | |
| 1707 | /// The 16-bit signed displacement of the target relative to the GP register. | |
| 1708 | GPREL = 0x0015, | |
| 1709 | /// The CLR token. | |
| 1710 | TOKEN = 0x0016, | |
| 1711 | _, | |
| 1712 | }; | |
| 1568 | 1713 | |
| 1569 | /// The 19-bit offset to the relocation target, for conditional B instruction. | |
| 1570 | branch19 = 15, | |
| 1714 | /// Intel 386 Processors | |
| 1715 | /// The following relocation type indicators are defined for Intel 386 and compatible processors. | |
| 1716 | pub const I386 = enum(u16) { | |
| 1717 | /// The relocation is ignored. | |
| 1718 | ABSOLUTE = 0x0000, | |
| 1719 | /// Not supported. | |
| 1720 | DIR16 = 0x0001, | |
| 1721 | /// Not supported. | |
| 1722 | REL16 = 0x0002, | |
| 1723 | /// The target's 32-bit VA. | |
| 1724 | DIR32 = 0x0006, | |
| 1725 | /// The target's 32-bit RVA. | |
| 1726 | DIR32NB = 0x0007, | |
| 1727 | /// Not supported. | |
| 1728 | SEG12 = 0x0009, | |
| 1729 | /// The 16-bit section index of the section that contains the target. | |
| 1730 | /// This is used to support debugging information. | |
| 1731 | SECTION = 0x000A, | |
| 1732 | /// The 32-bit offset of the target from the beginning of its section. | |
| 1733 | /// This is used to support debugging information and static thread local storage. | |
| 1734 | SECREL = 0x000B, | |
| 1735 | /// The CLR token. | |
| 1736 | TOKEN = 0x000C, | |
| 1737 | /// A 7-bit offset from the base of the section that contains the target. | |
| 1738 | SECREL7 = 0x000D, | |
| 1739 | /// The 32-bit relative displacement to the target. | |
| 1740 | /// This supports the x86 relative branch and call instructions. | |
| 1741 | REL32 = 0x0014, | |
| 1742 | _, | |
| 1743 | }; | |
| 1571 | 1744 | |
| 1572 | /// The 14-bit offset to the relocation target, for instructions TBZ and TBNZ. | |
| 1573 | branch14 = 16, | |
| 1745 | /// Intel Itanium Processor Family (IPF) | |
| 1746 | /// The following relocation type indicators are defined for the Intel Itanium processor family and compatible processors. | |
| 1747 | /// Note that relocations on instructions use the bundle's offset and slot number for the relocation offset. | |
| 1748 | pub const IA64 = enum(u16) { | |
| 1749 | /// The relocation is ignored. | |
| 1750 | ABSOLUTE = 0x0000, | |
| 1751 | /// 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. | |
| 1752 | /// The relocation target must be absolute or the image must be fixed. | |
| 1753 | IMM14 = 0x0001, | |
| 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 IMM22 bundle. | |
| 1755 | /// The relocation target must be absolute or the image must be fixed. | |
| 1756 | IMM22 = 0x0002, | |
| 1757 | /// The slot number of this relocation must be one (1). | |
| 1758 | /// 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. | |
| 1759 | IMM64 = 0x0003, | |
| 1760 | /// The target's 32-bit VA. | |
| 1761 | /// This is supported only for /LARGEADDRESSAWARE:NO images. | |
| 1762 | DIR32 = 0x0004, | |
| 1763 | /// The target's 64-bit VA. | |
| 1764 | DIR64 = 0x0005, | |
| 1765 | /// The instruction is fixed up with the 25-bit relative displacement to the 16-bit aligned target. | |
| 1766 | /// The low 4 bits of the displacement are zero and are not stored. | |
| 1767 | PCREL21B = 0x0006, | |
| 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, which are zero, are not stored. | |
| 1770 | PCREL21M = 0x0007, | |
| 1771 | /// The LSBs of this relocation's offset must contain the slot number whereas the rest is the bundle address. | |
| 1772 | /// The bundle is fixed up with the 25-bit relative displacement to the 16-bit aligned target. | |
| 1773 | /// The low 4 bits of the displacement are zero and are not stored. | |
| 1774 | PCREL21F = 0x0008, | |
| 1775 | /// 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. | |
| 1776 | GPREL22 = 0x0009, | |
| 1777 | /// The instruction is fixed up with the 22-bit GP-relative offset to the target symbol's literal table entry. | |
| 1778 | /// The linker creates this literal table entry based on this relocation and the ADDEND relocation that might follow. | |
| 1779 | LTOFF22 = 0x000A, | |
| 1780 | /// The 16-bit section index of the section contains the target. | |
| 1781 | /// This is used to support debugging information. | |
| 1782 | SECTION = 0x000B, | |
| 1783 | /// The instruction is fixed up with the 22-bit offset of the target from the beginning of its section. | |
| 1784 | /// 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. | |
| 1785 | SECREL22 = 0x000C, | |
| 1786 | /// The slot number for this relocation must be one (1). | |
| 1787 | /// The instruction is fixed up with the 64-bit offset of the target from the beginning of its section. | |
| 1788 | /// 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. | |
| 1789 | SECREL64I = 0x000D, | |
| 1790 | /// The address of data to be fixed up with the 32-bit offset of the target from the beginning of its section. | |
| 1791 | SECREL32 = 0x000E, | |
| 1792 | /// The target's 32-bit RVA. | |
| 1793 | DIR32NB = 0x0010, | |
| 1794 | /// This is applied to a signed 14-bit immediate that contains the difference between two relocatable targets. | |
| 1795 | /// This is a declarative field for the linker that indicates that the compiler has already emitted this value. | |
| 1796 | SREL14 = 0x0011, | |
| 1797 | /// This is applied to a signed 22-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 | SREL22 = 0x0012, | |
| 1800 | /// This is applied to a signed 32-bit immediate that contains the difference between two relocatable values. | |
| 1801 | /// This is a declarative field for the linker that indicates that the compiler has already emitted this value. | |
| 1802 | SREL32 = 0x0013, | |
| 1803 | /// This is applied to an unsigned 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 | UREL32 = 0x0014, | |
| 1806 | /// A 60-bit PC-relative fixup that always stays as a BRL instruction of an MLX bundle. | |
| 1807 | PCREL60X = 0x0015, | |
| 1808 | /// A 60-bit PC-relative fixup. | |
| 1809 | /// 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. | |
| 1810 | PCREL60B = 0x0016, | |
| 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 MFB bundle with NOP.F in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2. | |
| 1813 | PCREL60F = 0x0017, | |
| 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 MIB bundle with NOP.I in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2. | |
| 1816 | PCREL60I = 0x0018, | |
| 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 MMB bundle with NOP.M in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2. | |
| 1819 | PCREL60M = 0x0019, | |
| 1820 | /// A 64-bit GP-relative fixup. | |
| 1821 | IMMGPREL64 = 0x001a, | |
| 1822 | /// A CLR token. | |
| 1823 | TOKEN = 0x001b, | |
| 1824 | /// A 32-bit GP-relative fixup. | |
| 1825 | GPREL32 = 0x001c, | |
| 1826 | /// The relocation is valid only when it immediately follows one of the following relocations: IMM14, IMM22, IMM64, GPREL22, LTOFF22, LTOFF64, SECREL22, SECREL64I, or SECREL32. | |
| 1827 | /// Its value contains the addend to apply to instructions within a bundle, not for data. | |
| 1828 | ADDEND = 0x001F, | |
| 1829 | _, | |
| 1830 | }; | |
| 1574 | 1831 | |
| 1575 | /// The 32-bit relative address from the byte following the relocation. | |
| 1576 | rel32 = 17, | |
| 1832 | /// MIPS Processors | |
| 1833 | /// The following relocation type indicators are defined for MIPS processors. | |
| 1834 | pub const MIPS = enum(u16) { | |
| 1835 | /// The relocation is ignored. | |
| 1836 | ABSOLUTE = 0x0000, | |
| 1837 | /// The high 16 bits of the target's 32-bit VA. | |
| 1838 | REFHALF = 0x0001, | |
| 1839 | /// The target's 32-bit VA. | |
| 1840 | REFWORD = 0x0002, | |
| 1841 | /// The low 26 bits of the target's VA. | |
| 1842 | /// This supports the MIPS J and JAL instructions. | |
| 1843 | JMPADDR = 0x0003, | |
| 1844 | /// The high 16 bits of the target's 32-bit VA. | |
| 1845 | /// This is used for the first instruction in a two-instruction sequence that loads a full address. | |
| 1846 | /// 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. | |
| 1847 | REFHI = 0x0004, | |
| 1848 | /// The low 16 bits of the target's VA. | |
| 1849 | REFLO = 0x0005, | |
| 1850 | /// A 16-bit signed displacement of the target relative to the GP register. | |
| 1851 | GPREL = 0x0006, | |
| 1852 | /// The same as IMAGE_REL_MIPS_GPREL. | |
| 1853 | LITERAL = 0x0007, | |
| 1854 | /// The 16-bit section index of the section contains the target. | |
| 1855 | /// This is used to support debugging information. | |
| 1856 | SECTION = 0x000A, | |
| 1857 | /// The 32-bit offset of the target from the beginning of its section. | |
| 1858 | /// This is used to support debugging information and static thread local storage. | |
| 1859 | SECREL = 0x000B, | |
| 1860 | /// The low 16 bits of the 32-bit offset of the target from the beginning of its section. | |
| 1861 | SECRELLO = 0x000C, | |
| 1862 | /// The high 16 bits of the 32-bit offset of the target from the beginning of its section. | |
| 1863 | /// An IMAGE_REL_MIPS_PAIR relocation must immediately follow this one. | |
| 1864 | /// 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. | |
| 1865 | SECRELHI = 0x000D, | |
| 1866 | /// The low 26 bits of the target's VA. | |
| 1867 | /// This supports the MIPS16 JAL instruction. | |
| 1868 | JMPADDR16 = 0x0010, | |
| 1869 | /// The target's 32-bit RVA. | |
| 1870 | REFWORDNB = 0x0022, | |
| 1871 | /// The relocation is valid only when it immediately follows a REFHI or SECRELHI relocation. | |
| 1872 | /// Its SymbolTableIndex contains a displacement and not an index into the symbol table. | |
| 1873 | PAIR = 0x0025, | |
| 1874 | _, | |
| 1875 | }; | |
| 1577 | 1876 | |
| 1578 | _, | |
| 1877 | /// Mitsubishi M32R | |
| 1878 | /// The following relocation type indicators are defined for the Mitsubishi M32R processors. | |
| 1879 | pub const M32R = enum(u16) { | |
| 1880 | /// The relocation is ignored. | |
| 1881 | ABSOLUTE = 0x0000, | |
| 1882 | /// The target's 32-bit VA. | |
| 1883 | ADDR32 = 0x0001, | |
| 1884 | /// The target's 32-bit RVA. | |
| 1885 | ADDR32NB = 0x0002, | |
| 1886 | /// The target's 24-bit VA. | |
| 1887 | ADDR24 = 0x0003, | |
| 1888 | /// The target's 16-bit offset from the GP register. | |
| 1889 | GPREL16 = 0x0004, | |
| 1890 | /// The target's 24-bit offset from the program counter (PC), shifted left by 2 bits and sign-extended | |
| 1891 | PCREL24 = 0x0005, | |
| 1892 | /// The target's 16-bit offset from the PC, shifted left by 2 bits and sign-extended | |
| 1893 | PCREL16 = 0x0006, | |
| 1894 | /// The target's 8-bit offset from the PC, shifted left by 2 bits and sign-extended | |
| 1895 | PCREL8 = 0x0007, | |
| 1896 | /// The 16 MSBs of the target VA. | |
| 1897 | REFHALF = 0x0008, | |
| 1898 | /// The 16 MSBs of the target VA, adjusted for LSB sign extension. | |
| 1899 | /// This is used for the first instruction in a two-instruction sequence that loads a full 32-bit address. | |
| 1900 | /// 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. | |
| 1901 | REFHI = 0x0009, | |
| 1902 | /// The 16 LSBs of the target VA. | |
| 1903 | REFLO = 0x000A, | |
| 1904 | /// The relocation must follow the REFHI relocation. | |
| 1905 | /// Its SymbolTableIndex contains a displacement and not an index into the symbol table. | |
| 1906 | PAIR = 0x000B, | |
| 1907 | /// The 16-bit section index of the section that contains the target. | |
| 1908 | /// This is used to support debugging information. | |
| 1909 | SECTION = 0x000C, | |
| 1910 | /// The 32-bit offset of the target from the beginning of its section. | |
| 1911 | /// This is used to support debugging information and static thread local storage. | |
| 1912 | SECREL = 0x000D, | |
| 1913 | /// The CLR token. | |
| 1914 | TOKEN = 0x000E, | |
| 1915 | _, | |
| 1916 | }; | |
| 1917 | }; | |
| 1579 | 1918 | }; |
lib/std/heap.zig+21-12| ... | ... | @@ -78,13 +78,15 @@ pub fn defaultQueryPageSize() usize { |
| 78 | 78 | }; |
| 79 | 79 | var size = global.cached_result.load(.unordered); |
| 80 | 80 | if (size > 0) return size; |
| 81 | size = switch (builtin.os.tag) { | |
| 82 | .linux => if (builtin.link_libc) @intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE))) else std.os.linux.getauxval(std.elf.AT_PAGESZ), | |
| 83 | .driverkit, .ios, .macos, .tvos, .visionos, .watchos => blk: { | |
| 81 | size = size: switch (builtin.os.tag) { | |
| 82 | .linux => if (builtin.link_libc) | |
| 83 | @max(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE)), 0) | |
| 84 | else | |
| 85 | std.os.linux.getauxval(std.elf.AT_PAGESZ), | |
| 86 | .driverkit, .ios, .macos, .tvos, .visionos, .watchos => { | |
| 84 | 87 | const task_port = std.c.mach_task_self(); |
| 85 | 88 | // mach_task_self may fail "if there are any resource failures or other errors". |
| 86 | if (task_port == std.c.TASK.NULL) | |
| 87 | break :blk 0; | |
| 89 | if (task_port == std.c.TASK.NULL) break :size 0; | |
| 88 | 90 | var info_count = std.c.TASK.VM.INFO_COUNT; |
| 89 | 91 | var vm_info: std.c.task_vm_info_data_t = undefined; |
| 90 | 92 | vm_info.page_size = 0; |
| ... | ... | @@ -94,21 +96,28 @@ pub fn defaultQueryPageSize() usize { |
| 94 | 96 | @as(std.c.task_info_t, @ptrCast(&vm_info)), |
| 95 | 97 | &info_count, |
| 96 | 98 | ); |
| 97 | assert(vm_info.page_size != 0); | |
| 98 | break :blk @intCast(vm_info.page_size); | |
| 99 | break :size @intCast(vm_info.page_size); | |
| 99 | 100 | }, |
| 100 | .windows => blk: { | |
| 101 | var info: std.os.windows.SYSTEM_INFO = undefined; | |
| 102 | std.os.windows.kernel32.GetSystemInfo(&info); | |
| 103 | break :blk info.dwPageSize; | |
| 101 | .windows => { | |
| 102 | var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined; | |
| 103 | switch (windows.ntdll.NtQuerySystemInformation( | |
| 104 | .SystemBasicInformation, | |
| 105 | &sbi, | |
| 106 | @sizeOf(windows.SYSTEM_BASIC_INFORMATION), | |
| 107 | null, | |
| 108 | )) { | |
| 109 | .SUCCESS => break :size sbi.PageSize, | |
| 110 | else => break :size 0, | |
| 111 | } | |
| 104 | 112 | }, |
| 105 | 113 | else => if (builtin.link_libc) |
| 106 | @intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE))) | |
| 114 | @max(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE)), 0) | |
| 107 | 115 | else if (builtin.os.tag == .freestanding or builtin.os.tag == .other) |
| 108 | 116 | @compileError("unsupported target: freestanding/other") |
| 109 | 117 | else |
| 110 | 118 | @compileError("pageSize on " ++ @tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " is not supported without linking libc, using the default implementation"), |
| 111 | 119 | }; |
| 120 | if (size == 0) size = page_size_max; | |
| 112 | 121 | |
| 113 | 122 | assert(size >= page_size_min); |
| 114 | 123 | assert(size <= page_size_max); |
src/Compilation.zig+17-9| ... | ... | @@ -256,8 +256,8 @@ test_filters: []const []const u8, |
| 256 | 256 | |
| 257 | 257 | link_task_wait_group: WaitGroup = .{}, |
| 258 | 258 | link_prog_node: std.Progress.Node = .none, |
| 259 | link_uav_prog_node: std.Progress.Node = .none, | |
| 260 | link_lazy_prog_node: std.Progress.Node = .none, | |
| 259 | link_const_prog_node: std.Progress.Node = .none, | |
| 260 | link_synth_prog_node: std.Progress.Node = .none, | |
| 261 | 261 | |
| 262 | 262 | llvm_opt_bisect_limit: c_int, |
| 263 | 263 | |
| ... | ... | @@ -1982,13 +1982,13 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options |
| 1982 | 1982 | }; |
| 1983 | 1983 | if (have_zcu and (!need_llvm or use_llvm)) { |
| 1984 | 1984 | if (output_mode == .Obj) break :s .zcu; |
| 1985 | if (options.config.use_new_linker) break :s .zcu; | |
| 1986 | 1985 | switch (target_util.zigBackend(target, use_llvm)) { |
| 1987 | 1986 | else => {}, |
| 1988 | 1987 | .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) { |
| 1989 | 1988 | break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu; |
| 1990 | 1989 | }, |
| 1991 | 1990 | } |
| 1991 | if (options.config.use_new_linker) break :s .zcu; | |
| 1992 | 1992 | } |
| 1993 | 1993 | if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm |
| 1994 | 1994 | if (is_exe_or_dyn_lib) break :s .lib; |
| ... | ... | @@ -3081,22 +3081,30 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 3081 | 3081 | comp.link_prog_node = main_progress_node.start("Linking", 0); |
| 3082 | 3082 | if (lf.cast(.elf2)) |elf| { |
| 3083 | 3083 | comp.link_prog_node.increaseEstimatedTotalItems(3); |
| 3084 | comp.link_uav_prog_node = comp.link_prog_node.start("Constants", 0); | |
| 3085 | comp.link_lazy_prog_node = comp.link_prog_node.start("Synthetics", 0); | |
| 3084 | comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0); | |
| 3085 | comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0); | |
| 3086 | 3086 | elf.mf.update_prog_node = comp.link_prog_node.start("Relocations", elf.mf.updates.items.len); |
| 3087 | } else if (lf.cast(.coff2)) |coff| { | |
| 3088 | comp.link_prog_node.increaseEstimatedTotalItems(3); | |
| 3089 | comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0); | |
| 3090 | comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0); | |
| 3091 | coff.mf.update_prog_node = comp.link_prog_node.start("Relocations", coff.mf.updates.items.len); | |
| 3087 | 3092 | } |
| 3088 | 3093 | } |
| 3089 | 3094 | defer { |
| 3090 | 3095 | comp.link_prog_node.end(); |
| 3091 | 3096 | comp.link_prog_node = .none; |
| 3092 | comp.link_uav_prog_node.end(); | |
| 3093 | comp.link_uav_prog_node = .none; | |
| 3094 | comp.link_lazy_prog_node.end(); | |
| 3095 | comp.link_lazy_prog_node = .none; | |
| 3097 | comp.link_const_prog_node.end(); | |
| 3098 | comp.link_const_prog_node = .none; | |
| 3099 | comp.link_synth_prog_node.end(); | |
| 3100 | comp.link_synth_prog_node = .none; | |
| 3096 | 3101 | if (comp.bin_file) |lf| { |
| 3097 | 3102 | if (lf.cast(.elf2)) |elf| { |
| 3098 | 3103 | elf.mf.update_prog_node.end(); |
| 3099 | 3104 | elf.mf.update_prog_node = .none; |
| 3105 | } else if (lf.cast(.coff2)) |coff| { | |
| 3106 | coff.mf.update_prog_node.end(); | |
| 3107 | coff.mf.update_prog_node = .none; | |
| 3100 | 3108 | } |
| 3101 | 3109 | } |
| 3102 | 3110 | } |
src/Compilation/Config.zig+2| ... | ... | @@ -438,6 +438,8 @@ pub fn resolve(options: Options) ResolveError!Config { |
| 438 | 438 | |
| 439 | 439 | if (options.use_new_linker) |x| break :b x; |
| 440 | 440 | |
| 441 | if (target.ofmt == .coff) break :b true; | |
| 442 | ||
| 441 | 443 | break :b options.incremental; |
| 442 | 444 | }; |
| 443 | 445 |
src/InternPool.zig+3-3| ... | ... | @@ -11919,10 +11919,10 @@ pub fn getString(ip: *InternPool, key: []const u8) OptionalNullTerminatedString |
| 11919 | 11919 | var map_index = hash; |
| 11920 | 11920 | while (true) : (map_index += 1) { |
| 11921 | 11921 | map_index &= map_mask; |
| 11922 | const entry = map.at(map_index); | |
| 11923 | const index = entry.acquire().unwrap() orelse return null; | |
| 11922 | const entry = &map.entries[map_index]; | |
| 11923 | const index = entry.value.unwrap() orelse return .none; | |
| 11924 | 11924 | if (entry.hash != hash) continue; |
| 11925 | if (index.eqlSlice(key, ip)) return index; | |
| 11925 | if (index.eqlSlice(key, ip)) return index.toOptional(); | |
| 11926 | 11926 | } |
| 11927 | 11927 | } |
| 11928 | 11928 |
src/codegen.zig+2| ... | ... | @@ -993,6 +993,8 @@ pub fn genNavRef( |
| 993 | 993 | }, |
| 994 | 994 | .link_once => unreachable, |
| 995 | 995 | } |
| 996 | } else if (lf.cast(.coff2)) |coff| { | |
| 997 | return .{ .sym_index = @intFromEnum(try coff.navSymbol(zcu, nav_index)) }; | |
| 996 | 998 | } else { |
| 997 | 999 | const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target}); |
| 998 | 1000 | return .{ .fail = msg }; |
src/codegen/x86_64/Emit.zig+41-10| ... | ... | @@ -89,6 +89,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 89 | 89 | } |
| 90 | 90 | var reloc_info_buf: [2]RelocInfo = undefined; |
| 91 | 91 | var reloc_info_index: usize = 0; |
| 92 | const ip = &emit.pt.zcu.intern_pool; | |
| 92 | 93 | while (lowered_relocs.len > 0 and |
| 93 | 94 | lowered_relocs[0].lowered_inst_index == lowered_index) : ({ |
| 94 | 95 | lowered_relocs = lowered_relocs[1..]; |
| ... | ... | @@ -114,7 +115,6 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 114 | 115 | return error.EmitFail; |
| 115 | 116 | }, |
| 116 | 117 | }; |
| 117 | const ip = &emit.pt.zcu.intern_pool; | |
| 118 | 118 | break :target switch (ip.getNav(nav).status) { |
| 119 | 119 | .unresolved => unreachable, |
| 120 | 120 | .type_resolved => |type_resolved| .{ |
| ... | ... | @@ -175,6 +175,8 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 175 | 175 | coff_file.getAtom(atom).getSymbolIndex().? |
| 176 | 176 | else |err| |
| 177 | 177 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) |
| 178 | else if (emit.bin_file.cast(.coff2)) |elf| | |
| 179 | @intFromEnum(try elf.lazySymbol(lazy_sym)) | |
| 178 | 180 | else |
| 179 | 181 | return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), |
| 180 | 182 | .is_extern = false, |
| ... | ... | @@ -190,8 +192,13 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 190 | 192 | try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) |
| 191 | 193 | else if (emit.bin_file.cast(.coff)) |coff_file| |
| 192 | 194 | try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt") |
| 193 | else | |
| 194 | return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), | |
| 195 | else if (emit.bin_file.cast(.coff2)) |coff| @intFromEnum(try coff.globalSymbol( | |
| 196 | extern_func.toSlice(&emit.lower.mir).?, | |
| 197 | switch (comp.compiler_rt_strat) { | |
| 198 | .none, .lib, .obj, .zcu => null, | |
| 199 | .dyn_lib => "compiler_rt", | |
| 200 | }, | |
| 201 | )) else return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), | |
| 195 | 202 | .is_extern = true, |
| 196 | 203 | .type = .symbol, |
| 197 | 204 | }, |
| ... | ... | @@ -314,6 +321,18 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 314 | 321 | }, emit.lower.target), reloc_info), |
| 315 | 322 | else => unreachable, |
| 316 | 323 | } |
| 324 | } else if (emit.bin_file.cast(.coff2)) |_| { | |
| 325 | switch (lowered_inst.encoding.mnemonic) { | |
| 326 | .lea => try emit.encodeInst(try .new(.none, .lea, &.{ | |
| 327 | lowered_inst.ops[0], | |
| 328 | .{ .mem = .initRip(.none, 0) }, | |
| 329 | }, emit.lower.target), reloc_info), | |
| 330 | .mov => try emit.encodeInst(try .new(.none, .mov, &.{ | |
| 331 | lowered_inst.ops[0], | |
| 332 | .{ .mem = .initRip(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, 0) }, | |
| 333 | }, emit.lower.target), reloc_info), | |
| 334 | else => unreachable, | |
| 335 | } | |
| 317 | 336 | } else return emit.fail("TODO implement relocs for {s}", .{ |
| 318 | 337 | @tagName(emit.bin_file.tag), |
| 319 | 338 | }); |
| ... | ... | @@ -683,7 +702,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 683 | 702 | table_reloc.source_offset, |
| 684 | 703 | @enumFromInt(emit.atom_index), |
| 685 | 704 | @as(i64, table_offset) + table_reloc.target_offset, |
| 686 | .{ .x86_64 = .@"32" }, | |
| 705 | .{ .X86_64 = .@"32" }, | |
| 687 | 706 | ); |
| 688 | 707 | for (emit.lower.mir.table) |entry| { |
| 689 | 708 | try elf.addReloc( |
| ... | ... | @@ -691,7 +710,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 691 | 710 | table_offset, |
| 692 | 711 | @enumFromInt(emit.atom_index), |
| 693 | 712 | emit.code_offset_mapping.items[entry], |
| 694 | .{ .x86_64 = .@"64" }, | |
| 713 | .{ .X86_64 = .@"64" }, | |
| 695 | 714 | ); |
| 696 | 715 | table_offset += ptr_size; |
| 697 | 716 | } |
| ... | ... | @@ -800,7 +819,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 800 | 819 | end_offset - 4, |
| 801 | 820 | @enumFromInt(reloc.target.index), |
| 802 | 821 | reloc.off, |
| 803 | .{ .x86_64 = .@"32" }, | |
| 822 | .{ .X86_64 = .@"32" }, | |
| 804 | 823 | ) else if (emit.bin_file.cast(.coff)) |coff_file| { |
| 805 | 824 | const atom_index = coff_file.getAtomIndexForSymbol( |
| 806 | 825 | .{ .sym_index = emit.atom_index, .file = null }, |
| ... | ... | @@ -816,7 +835,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 816 | 835 | .pcrel = true, |
| 817 | 836 | .length = 2, |
| 818 | 837 | }); |
| 819 | } else unreachable, | |
| 838 | } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc( | |
| 839 | @enumFromInt(emit.atom_index), | |
| 840 | end_offset - 4, | |
| 841 | @enumFromInt(reloc.target.index), | |
| 842 | reloc.off, | |
| 843 | .{ .AMD64 = .REL32 }, | |
| 844 | ) else unreachable, | |
| 820 | 845 | .branch => if (emit.bin_file.cast(.elf)) |elf_file| { |
| 821 | 846 | const zo = elf_file.zigObjectPtr().?; |
| 822 | 847 | const atom = zo.symbol(emit.atom_index).atom(elf_file).?; |
| ... | ... | @@ -831,7 +856,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 831 | 856 | end_offset - 4, |
| 832 | 857 | @enumFromInt(reloc.target.index), |
| 833 | 858 | reloc.off - 4, |
| 834 | .{ .x86_64 = .PC32 }, | |
| 859 | .{ .X86_64 = .PC32 }, | |
| 835 | 860 | ) else if (emit.bin_file.cast(.macho)) |macho_file| { |
| 836 | 861 | const zo = macho_file.getZigObject().?; |
| 837 | 862 | const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; |
| ... | ... | @@ -863,7 +888,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 863 | 888 | .pcrel = true, |
| 864 | 889 | .length = 2, |
| 865 | 890 | }); |
| 866 | } else return emit.fail("TODO implement {s} reloc for {s}", .{ | |
| 891 | } else if (emit.bin_file.cast(.coff2)) |coff| try coff.addReloc( | |
| 892 | @enumFromInt(emit.atom_index), | |
| 893 | end_offset - 4, | |
| 894 | @enumFromInt(reloc.target.index), | |
| 895 | reloc.off, | |
| 896 | .{ .AMD64 = .REL32 }, | |
| 897 | ) else return emit.fail("TODO implement {s} reloc for {s}", .{ | |
| 867 | 898 | @tagName(reloc.target.type), @tagName(emit.bin_file.tag), |
| 868 | 899 | }), |
| 869 | 900 | .tls => if (emit.bin_file.cast(.elf)) |elf_file| { |
| ... | ... | @@ -892,7 +923,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 892 | 923 | end_offset - 4, |
| 893 | 924 | @enumFromInt(reloc.target.index), |
| 894 | 925 | reloc.off, |
| 895 | .{ .x86_64 = .TPOFF32 }, | |
| 926 | .{ .X86_64 = .TPOFF32 }, | |
| 896 | 927 | ) else if (emit.bin_file.cast(.macho)) |macho_file| { |
| 897 | 928 | const zo = macho_file.getZigObject().?; |
| 898 | 929 | const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; |
src/dev.zig+2| ... | ... | @@ -96,6 +96,7 @@ pub const Env = enum { |
| 96 | 96 | .spirv_backend, |
| 97 | 97 | .lld_linker, |
| 98 | 98 | .coff_linker, |
| 99 | .coff2_linker, | |
| 99 | 100 | .elf_linker, |
| 100 | 101 | .elf2_linker, |
| 101 | 102 | .macho_linker, |
| ... | ... | @@ -284,6 +285,7 @@ pub const Feature = enum { |
| 284 | 285 | |
| 285 | 286 | lld_linker, |
| 286 | 287 | coff_linker, |
| 288 | coff2_linker, | |
| 287 | 289 | elf_linker, |
| 288 | 290 | elf2_linker, |
| 289 | 291 | macho_linker, |
src/link.zig+35-39| ... | ... | @@ -610,27 +610,20 @@ pub const File = struct { |
| 610 | 610 | } |
| 611 | 611 | } |
| 612 | 612 | } |
| 613 | const output_mode = comp.config.output_mode; | |
| 614 | const link_mode = comp.config.link_mode; | |
| 615 | base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{ | |
| 616 | .truncate = false, | |
| 617 | .read = true, | |
| 618 | .mode = determineMode(output_mode, link_mode), | |
| 619 | }); | |
| 613 | base.file = try emit.root_dir.handle.openFile(emit.sub_path, .{ .mode = .read_write }); | |
| 620 | 614 | }, |
| 621 | .elf2 => { | |
| 622 | const elf = base.cast(.elf2).?; | |
| 623 | if (base.file == null) { | |
| 624 | elf.mf.file = try base.emit.root_dir.handle.createFile(base.emit.sub_path, .{ | |
| 625 | .truncate = false, | |
| 626 | .read = true, | |
| 627 | .mode = determineMode(comp.config.output_mode, comp.config.link_mode), | |
| 628 | }); | |
| 629 | base.file = elf.mf.file; | |
| 630 | try elf.mf.ensureTotalCapacity( | |
| 631 | @intCast(elf.mf.nodes.items[0].location().resolve(&elf.mf)[1]), | |
| 632 | ); | |
| 633 | } | |
| 615 | .elf2, .coff2 => if (base.file == null) { | |
| 616 | const mf = if (base.cast(.elf2)) |elf| | |
| 617 | &elf.mf | |
| 618 | else if (base.cast(.coff2)) |coff| | |
| 619 | &coff.mf | |
| 620 | else | |
| 621 | unreachable; | |
| 622 | mf.file = try base.emit.root_dir.handle.openFile(base.emit.sub_path, .{ | |
| 623 | .mode = .read_write, | |
| 624 | }); | |
| 625 | base.file = mf.file; | |
| 626 | try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1])); | |
| 634 | 627 | }, |
| 635 | 628 | .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), |
| 636 | 629 | .plan9 => unreachable, |
| ... | ... | @@ -654,12 +647,9 @@ pub const File = struct { |
| 654 | 647 | pub fn makeExecutable(base: *File) !void { |
| 655 | 648 | dev.check(.make_executable); |
| 656 | 649 | const comp = base.comp; |
| 657 | const output_mode = comp.config.output_mode; | |
| 658 | const link_mode = comp.config.link_mode; | |
| 659 | ||
| 660 | switch (output_mode) { | |
| 650 | switch (comp.config.output_mode) { | |
| 661 | 651 | .Obj => return, |
| 662 | .Lib => switch (link_mode) { | |
| 652 | .Lib => switch (comp.config.link_mode) { | |
| 663 | 653 | .static => return, |
| 664 | 654 | .dynamic => {}, |
| 665 | 655 | }, |
| ... | ... | @@ -702,15 +692,18 @@ pub const File = struct { |
| 702 | 692 | } |
| 703 | 693 | } |
| 704 | 694 | }, |
| 705 | .elf2 => { | |
| 706 | const elf = base.cast(.elf2).?; | |
| 707 | if (base.file) |f| { | |
| 708 | elf.mf.unmap(); | |
| 709 | assert(elf.mf.file.handle == f.handle); | |
| 710 | elf.mf.file = undefined; | |
| 711 | f.close(); | |
| 712 | base.file = null; | |
| 713 | } | |
| 695 | .elf2, .coff2 => if (base.file) |f| { | |
| 696 | const mf = if (base.cast(.elf2)) |elf| | |
| 697 | &elf.mf | |
| 698 | else if (base.cast(.coff2)) |coff| | |
| 699 | &coff.mf | |
| 700 | else | |
| 701 | unreachable; | |
| 702 | mf.unmap(); | |
| 703 | assert(mf.file.handle == f.handle); | |
| 704 | mf.file = undefined; | |
| 705 | f.close(); | |
| 706 | base.file = null; | |
| 714 | 707 | }, |
| 715 | 708 | .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), |
| 716 | 709 | .plan9 => unreachable, |
| ... | ... | @@ -828,7 +821,7 @@ pub const File = struct { |
| 828 | 821 | .spirv => {}, |
| 829 | 822 | .goff, .xcoff => {}, |
| 830 | 823 | .plan9 => unreachable, |
| 831 | .elf2 => {}, | |
| 824 | .elf2, .coff2 => {}, | |
| 832 | 825 | inline else => |tag| { |
| 833 | 826 | dev.check(tag.devFeature()); |
| 834 | 827 | return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); |
| ... | ... | @@ -864,7 +857,7 @@ pub const File = struct { |
| 864 | 857 | pub fn idle(base: *File, tid: Zcu.PerThread.Id) !bool { |
| 865 | 858 | switch (base.tag) { |
| 866 | 859 | else => return false, |
| 867 | inline .elf2 => |tag| { | |
| 860 | inline .elf2, .coff2 => |tag| { | |
| 868 | 861 | dev.check(tag.devFeature()); |
| 869 | 862 | return @as(*tag.Type(), @fieldParentPtr("base", base)).idle(tid); |
| 870 | 863 | }, |
| ... | ... | @@ -874,7 +867,7 @@ pub const File = struct { |
| 874 | 867 | pub fn updateErrorData(base: *File, pt: Zcu.PerThread) !void { |
| 875 | 868 | switch (base.tag) { |
| 876 | 869 | else => {}, |
| 877 | inline .elf2 => |tag| { | |
| 870 | inline .elf2, .coff2 => |tag| { | |
| 878 | 871 | dev.check(tag.devFeature()); |
| 879 | 872 | return @as(*tag.Type(), @fieldParentPtr("base", base)).updateErrorData(pt); |
| 880 | 873 | }, |
| ... | ... | @@ -1155,7 +1148,7 @@ pub const File = struct { |
| 1155 | 1148 | if (base.zcu_object_basename != null) return; |
| 1156 | 1149 | |
| 1157 | 1150 | switch (base.tag) { |
| 1158 | inline .elf2, .wasm => |tag| { | |
| 1151 | inline .elf2, .coff2, .wasm => |tag| { | |
| 1159 | 1152 | dev.check(tag.devFeature()); |
| 1160 | 1153 | return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node); |
| 1161 | 1154 | }, |
| ... | ... | @@ -1165,6 +1158,7 @@ pub const File = struct { |
| 1165 | 1158 | |
| 1166 | 1159 | pub const Tag = enum { |
| 1167 | 1160 | coff, |
| 1161 | coff2, | |
| 1168 | 1162 | elf, |
| 1169 | 1163 | elf2, |
| 1170 | 1164 | macho, |
| ... | ... | @@ -1179,6 +1173,7 @@ pub const File = struct { |
| 1179 | 1173 | pub fn Type(comptime tag: Tag) type { |
| 1180 | 1174 | return switch (tag) { |
| 1181 | 1175 | .coff => Coff, |
| 1176 | .coff2 => Coff2, | |
| 1182 | 1177 | .elf => Elf, |
| 1183 | 1178 | .elf2 => Elf2, |
| 1184 | 1179 | .macho => MachO, |
| ... | ... | @@ -1194,7 +1189,7 @@ pub const File = struct { |
| 1194 | 1189 | |
| 1195 | 1190 | fn fromObjectFormat(ofmt: std.Target.ObjectFormat, use_new_linker: bool) Tag { |
| 1196 | 1191 | return switch (ofmt) { |
| 1197 | .coff => .coff, | |
| 1192 | .coff => if (use_new_linker) .coff2 else .coff, | |
| 1198 | 1193 | .elf => if (use_new_linker) .elf2 else .elf, |
| 1199 | 1194 | .macho => .macho, |
| 1200 | 1195 | .wasm => .wasm, |
| ... | ... | @@ -1280,6 +1275,7 @@ pub const File = struct { |
| 1280 | 1275 | pub const Lld = @import("link/Lld.zig"); |
| 1281 | 1276 | pub const C = @import("link/C.zig"); |
| 1282 | 1277 | pub const Coff = @import("link/Coff.zig"); |
| 1278 | pub const Coff2 = @import("link/Coff2.zig"); | |
| 1283 | 1279 | pub const Elf = @import("link/Elf.zig"); |
| 1284 | 1280 | pub const Elf2 = @import("link/Elf2.zig"); |
| 1285 | 1281 | pub const MachO = @import("link/MachO.zig"); |
src/link/Coff.zig+41-41| ... | ... | @@ -125,11 +125,11 @@ const UavTable = std.AutoHashMapUnmanaged(InternPool.Index, AvMetadata); |
| 125 | 125 | const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); |
| 126 | 126 | const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); |
| 127 | 127 | |
| 128 | const default_file_alignment: u16 = 0x200; | |
| 129 | const default_size_of_stack_reserve: u32 = 0x1000000; | |
| 130 | const default_size_of_stack_commit: u32 = 0x1000; | |
| 131 | const default_size_of_heap_reserve: u32 = 0x100000; | |
| 132 | const default_size_of_heap_commit: u32 = 0x1000; | |
| 128 | pub const default_file_alignment: u16 = 0x200; | |
| 129 | pub const default_size_of_stack_reserve: u32 = 0x1000000; | |
| 130 | pub const default_size_of_stack_commit: u32 = 0x1000; | |
| 131 | pub const default_size_of_heap_reserve: u32 = 0x100000; | |
| 132 | pub const default_size_of_heap_commit: u32 = 0x1000; | |
| 133 | 133 | |
| 134 | 134 | const Section = struct { |
| 135 | 135 | header: coff_util.SectionHeader, |
| ... | ... | @@ -334,51 +334,51 @@ pub fn createEmpty( |
| 334 | 334 | if (coff.text_section_index == null) { |
| 335 | 335 | const file_size: u32 = @intCast(options.program_code_size_hint); |
| 336 | 336 | coff.text_section_index = try coff.allocateSection(".text", file_size, .{ |
| 337 | .CNT_CODE = 1, | |
| 338 | .MEM_EXECUTE = 1, | |
| 339 | .MEM_READ = 1, | |
| 337 | .CNT_CODE = true, | |
| 338 | .MEM_EXECUTE = true, | |
| 339 | .MEM_READ = true, | |
| 340 | 340 | }); |
| 341 | 341 | } |
| 342 | 342 | |
| 343 | 343 | if (coff.got_section_index == null) { |
| 344 | 344 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size(); |
| 345 | 345 | coff.got_section_index = try coff.allocateSection(".got", file_size, .{ |
| 346 | .CNT_INITIALIZED_DATA = 1, | |
| 347 | .MEM_READ = 1, | |
| 346 | .CNT_INITIALIZED_DATA = true, | |
| 347 | .MEM_READ = true, | |
| 348 | 348 | }); |
| 349 | 349 | } |
| 350 | 350 | |
| 351 | 351 | if (coff.rdata_section_index == null) { |
| 352 | 352 | const file_size: u32 = coff.page_size; |
| 353 | 353 | coff.rdata_section_index = try coff.allocateSection(".rdata", file_size, .{ |
| 354 | .CNT_INITIALIZED_DATA = 1, | |
| 355 | .MEM_READ = 1, | |
| 354 | .CNT_INITIALIZED_DATA = true, | |
| 355 | .MEM_READ = true, | |
| 356 | 356 | }); |
| 357 | 357 | } |
| 358 | 358 | |
| 359 | 359 | if (coff.data_section_index == null) { |
| 360 | 360 | const file_size: u32 = coff.page_size; |
| 361 | 361 | coff.data_section_index = try coff.allocateSection(".data", file_size, .{ |
| 362 | .CNT_INITIALIZED_DATA = 1, | |
| 363 | .MEM_READ = 1, | |
| 364 | .MEM_WRITE = 1, | |
| 362 | .CNT_INITIALIZED_DATA = true, | |
| 363 | .MEM_READ = true, | |
| 364 | .MEM_WRITE = true, | |
| 365 | 365 | }); |
| 366 | 366 | } |
| 367 | 367 | |
| 368 | 368 | if (coff.idata_section_index == null) { |
| 369 | 369 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size(); |
| 370 | 370 | coff.idata_section_index = try coff.allocateSection(".idata", file_size, .{ |
| 371 | .CNT_INITIALIZED_DATA = 1, | |
| 372 | .MEM_READ = 1, | |
| 371 | .CNT_INITIALIZED_DATA = true, | |
| 372 | .MEM_READ = true, | |
| 373 | 373 | }); |
| 374 | 374 | } |
| 375 | 375 | |
| 376 | 376 | if (coff.reloc_section_index == null) { |
| 377 | 377 | const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff_util.BaseRelocation); |
| 378 | 378 | coff.reloc_section_index = try coff.allocateSection(".reloc", file_size, .{ |
| 379 | .CNT_INITIALIZED_DATA = 1, | |
| 380 | .MEM_DISCARDABLE = 1, | |
| 381 | .MEM_READ = 1, | |
| 379 | .CNT_INITIALIZED_DATA = true, | |
| 380 | .MEM_DISCARDABLE = true, | |
| 381 | .MEM_READ = true, | |
| 382 | 382 | }); |
| 383 | 383 | } |
| 384 | 384 | |
| ... | ... | @@ -477,7 +477,7 @@ pub fn deinit(coff: *Coff) void { |
| 477 | 477 | coff.base_relocs.deinit(gpa); |
| 478 | 478 | } |
| 479 | 479 | |
| 480 | fn allocateSection(coff: *Coff, name: []const u8, size: u32, flags: coff_util.SectionHeaderFlags) !u16 { | |
| 480 | fn allocateSection(coff: *Coff, name: []const u8, size: u32, flags: coff_util.SectionHeader.Flags) !u16 { | |
| 481 | 481 | const index = @as(u16, @intCast(coff.sections.slice().len)); |
| 482 | 482 | const off = coff.findFreeSpace(size, default_file_alignment); |
| 483 | 483 | // Memory is always allocated in sequence |
| ... | ... | @@ -836,7 +836,7 @@ fn writeAtom(coff: *Coff, atom_index: Atom.Index, code: []u8, resolve_relocs: bo |
| 836 | 836 | try debugMem(gpa, handle, pvaddr, mem_code); |
| 837 | 837 | } |
| 838 | 838 | |
| 839 | if (section.header.flags.MEM_WRITE == 0) { | |
| 839 | if (!section.header.flags.MEM_WRITE) { | |
| 840 | 840 | writeMemProtected(handle, pvaddr, mem_code) catch |err| { |
| 841 | 841 | log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)}); |
| 842 | 842 | }; |
| ... | ... | @@ -2227,21 +2227,21 @@ fn writeHeader(coff: *Coff) !void { |
| 2227 | 2227 | mem.writeInt(u32, buffer.writer.buffer[0x3c..][0..4], msdos_stub.len, .little); |
| 2228 | 2228 | |
| 2229 | 2229 | writer.writeAll("PE\x00\x00") catch unreachable; |
| 2230 | var flags = coff_util.CoffHeaderFlags{ | |
| 2231 | .EXECUTABLE_IMAGE = 1, | |
| 2232 | .DEBUG_STRIPPED = 1, // TODO | |
| 2230 | var flags: coff_util.Header.Flags = .{ | |
| 2231 | .EXECUTABLE_IMAGE = true, | |
| 2232 | .DEBUG_STRIPPED = true, // TODO | |
| 2233 | 2233 | }; |
| 2234 | 2234 | switch (coff.ptr_width) { |
| 2235 | .p32 => flags.@"32BIT_MACHINE" = 1, | |
| 2236 | .p64 => flags.LARGE_ADDRESS_AWARE = 1, | |
| 2235 | .p32 => flags.@"32BIT_MACHINE" = true, | |
| 2236 | .p64 => flags.LARGE_ADDRESS_AWARE = true, | |
| 2237 | 2237 | } |
| 2238 | 2238 | if (coff.base.comp.config.output_mode == .Lib and coff.base.comp.config.link_mode == .dynamic) { |
| 2239 | flags.DLL = 1; | |
| 2239 | flags.DLL = true; | |
| 2240 | 2240 | } |
| 2241 | 2241 | |
| 2242 | 2242 | const timestamp = if (coff.repro) 0 else std.time.timestamp(); |
| 2243 | 2243 | const size_of_optional_header = @as(u16, @intCast(coff.getOptionalHeaderSize() + coff.getDataDirectoryHeadersSize())); |
| 2244 | var coff_header = coff_util.CoffHeader{ | |
| 2244 | var coff_header: coff_util.Header = .{ | |
| 2245 | 2245 | .machine = target.toCoffMachine(), |
| 2246 | 2246 | .number_of_sections = @as(u16, @intCast(coff.sections.slice().len)), // TODO what if we prune a section |
| 2247 | 2247 | .time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))), |
| ... | ... | @@ -2254,10 +2254,10 @@ fn writeHeader(coff: *Coff) !void { |
| 2254 | 2254 | writer.writeAll(mem.asBytes(&coff_header)) catch unreachable; |
| 2255 | 2255 | |
| 2256 | 2256 | const dll_flags: coff_util.DllFlags = .{ |
| 2257 | .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all? | |
| 2258 | .DYNAMIC_BASE = 1, | |
| 2259 | .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app | |
| 2260 | .NX_COMPAT = 1, // We are compatible with Data Execution Prevention | |
| 2257 | .HIGH_ENTROPY_VA = true, // TODO do we want to permit non-PIE builds at all? | |
| 2258 | .DYNAMIC_BASE = true, | |
| 2259 | .TERMINAL_SERVER_AWARE = true, // We are not a legacy app | |
| 2260 | .NX_COMPAT = true, // We are compatible with Data Execution Prevention | |
| 2261 | 2261 | }; |
| 2262 | 2262 | const subsystem: coff_util.Subsystem = .WINDOWS_CUI; |
| 2263 | 2263 | const size_of_image: u32 = coff.getSizeOfImage(); |
| ... | ... | @@ -2269,13 +2269,13 @@ fn writeHeader(coff: *Coff) !void { |
| 2269 | 2269 | var size_of_initialized_data: u32 = 0; |
| 2270 | 2270 | var size_of_uninitialized_data: u32 = 0; |
| 2271 | 2271 | for (coff.sections.items(.header)) |header| { |
| 2272 | if (header.flags.CNT_CODE == 1) { | |
| 2272 | if (header.flags.CNT_CODE) { | |
| 2273 | 2273 | size_of_code += header.size_of_raw_data; |
| 2274 | 2274 | } |
| 2275 | if (header.flags.CNT_INITIALIZED_DATA == 1) { | |
| 2275 | if (header.flags.CNT_INITIALIZED_DATA) { | |
| 2276 | 2276 | size_of_initialized_data += header.size_of_raw_data; |
| 2277 | 2277 | } |
| 2278 | if (header.flags.CNT_UNINITIALIZED_DATA == 1) { | |
| 2278 | if (header.flags.CNT_UNINITIALIZED_DATA) { | |
| 2279 | 2279 | size_of_uninitialized_data += header.size_of_raw_data; |
| 2280 | 2280 | } |
| 2281 | 2281 | } |
| ... | ... | @@ -2283,7 +2283,7 @@ fn writeHeader(coff: *Coff) !void { |
| 2283 | 2283 | switch (coff.ptr_width) { |
| 2284 | 2284 | .p32 => { |
| 2285 | 2285 | var opt_header = coff_util.OptionalHeaderPE32{ |
| 2286 | .magic = coff_util.IMAGE_NT_OPTIONAL_HDR32_MAGIC, | |
| 2286 | .magic = .PE32, | |
| 2287 | 2287 | .major_linker_version = 0, |
| 2288 | 2288 | .minor_linker_version = 0, |
| 2289 | 2289 | .size_of_code = size_of_code, |
| ... | ... | @@ -2318,7 +2318,7 @@ fn writeHeader(coff: *Coff) !void { |
| 2318 | 2318 | }, |
| 2319 | 2319 | .p64 => { |
| 2320 | 2320 | var opt_header = coff_util.OptionalHeaderPE64{ |
| 2321 | .magic = coff_util.IMAGE_NT_OPTIONAL_HDR64_MAGIC, | |
| 2321 | .magic = .@"PE32+", | |
| 2322 | 2322 | .major_linker_version = 0, |
| 2323 | 2323 | .minor_linker_version = 0, |
| 2324 | 2324 | .size_of_code = size_of_code, |
| ... | ... | @@ -2422,7 +2422,7 @@ fn allocatedVirtualSize(coff: *Coff, start: u32) u32 { |
| 2422 | 2422 | |
| 2423 | 2423 | fn getSizeOfHeaders(coff: Coff) u32 { |
| 2424 | 2424 | const msdos_hdr_size = msdos_stub.len + 4; |
| 2425 | return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.CoffHeader) + coff.getOptionalHeaderSize() + | |
| 2425 | return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.Header) + coff.getOptionalHeaderSize() + | |
| 2426 | 2426 | coff.getDataDirectoryHeadersSize() + coff.getSectionHeadersSize())); |
| 2427 | 2427 | } |
| 2428 | 2428 | |
| ... | ... | @@ -2443,7 +2443,7 @@ fn getSectionHeadersSize(coff: Coff) u32 { |
| 2443 | 2443 | |
| 2444 | 2444 | fn getDataDirectoryHeadersOffset(coff: Coff) u32 { |
| 2445 | 2445 | const msdos_hdr_size = msdos_stub.len + 4; |
| 2446 | return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.CoffHeader) + coff.getOptionalHeaderSize())); | |
| 2446 | return @as(u32, @intCast(msdos_hdr_size + @sizeOf(coff_util.Header) + coff.getOptionalHeaderSize())); | |
| 2447 | 2447 | } |
| 2448 | 2448 | |
| 2449 | 2449 | fn getSectionHeadersOffset(coff: Coff) u32 { |
| ... | ... | @@ -3116,7 +3116,7 @@ fn pwriteAll(coff: *Coff, bytes: []const u8, offset: u64) error{LinkFailure}!voi |
| 3116 | 3116 | /// A "page" is 512 bytes. |
| 3117 | 3117 | /// A "long" is 4 bytes. |
| 3118 | 3118 | /// A "word" is 2 bytes. |
| 3119 | const msdos_stub: [120]u8 = .{ | |
| 3119 | pub const msdos_stub: [120]u8 = .{ | |
| 3120 | 3120 | 'M', 'Z', // Magic number. Stands for Mark Zbikowski (designer of the MS-DOS executable format). |
| 3121 | 3121 | 0x78, 0x00, // Number of bytes in the last page. This matches the size of this entire MS-DOS stub. |
| 3122 | 3122 | 0x01, 0x00, // Number of pages. |
src/link/Coff2.zig created+2128| ... | ... | @@ -0,0 +1,2128 @@ |
| 1 | base: link.File, | |
| 2 | endian: std.builtin.Endian, | |
| 3 | mf: MappedFile, | |
| 4 | nodes: std.MultiArrayList(Node), | |
| 5 | import_table: ImportTable, | |
| 6 | strings: std.HashMapUnmanaged( | |
| 7 | u32, | |
| 8 | void, | |
| 9 | std.hash_map.StringIndexContext, | |
| 10 | std.hash_map.default_max_load_percentage, | |
| 11 | ), | |
| 12 | string_bytes: std.ArrayList(u8), | |
| 13 | section_table: std.ArrayList(Symbol.Index), | |
| 14 | symbol_table: std.ArrayList(Symbol), | |
| 15 | globals: std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index), | |
| 16 | global_pending_index: u32, | |
| 17 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), | |
| 18 | uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | |
| 19 | lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { | |
| 20 | map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | |
| 21 | pending_index: u32, | |
| 22 | }), | |
| 23 | pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { | |
| 24 | alignment: InternPool.Alignment, | |
| 25 | src_loc: Zcu.LazySrcLoc, | |
| 26 | }), | |
| 27 | relocs: std.ArrayList(Reloc), | |
| 28 | /// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly. | |
| 29 | entry_hack: Symbol.Index, | |
| 30 | ||
| 31 | pub const Node = union(enum) { | |
| 32 | file, | |
| 33 | header, | |
| 34 | signature, | |
| 35 | coff_header, | |
| 36 | optional_header, | |
| 37 | data_directories, | |
| 38 | section_table, | |
| 39 | section: Symbol.Index, | |
| 40 | import_directory_table, | |
| 41 | import_lookup_table: u32, | |
| 42 | import_address_table: u32, | |
| 43 | import_hint_name_table: u32, | |
| 44 | global: GlobalMapIndex, | |
| 45 | nav: NavMapIndex, | |
| 46 | uav: UavMapIndex, | |
| 47 | lazy_code: LazyMapRef.Index(.code), | |
| 48 | lazy_const_data: LazyMapRef.Index(.const_data), | |
| 49 | ||
| 50 | pub const GlobalMapIndex = enum(u32) { | |
| 51 | _, | |
| 52 | ||
| 53 | pub fn globalName(gmi: GlobalMapIndex, coff: *const Coff) GlobalName { | |
| 54 | return coff.globals.keys()[@intFromEnum(gmi)]; | |
| 55 | } | |
| 56 | ||
| 57 | pub fn symbol(gmi: GlobalMapIndex, coff: *const Coff) Symbol.Index { | |
| 58 | return coff.globals.values()[@intFromEnum(gmi)]; | |
| 59 | } | |
| 60 | }; | |
| 61 | ||
| 62 | pub const NavMapIndex = enum(u32) { | |
| 63 | _, | |
| 64 | ||
| 65 | pub fn navIndex(nmi: NavMapIndex, coff: *const Coff) InternPool.Nav.Index { | |
| 66 | return coff.navs.keys()[@intFromEnum(nmi)]; | |
| 67 | } | |
| 68 | ||
| 69 | pub fn symbol(nmi: NavMapIndex, coff: *const Coff) Symbol.Index { | |
| 70 | return coff.navs.values()[@intFromEnum(nmi)]; | |
| 71 | } | |
| 72 | }; | |
| 73 | ||
| 74 | pub const UavMapIndex = enum(u32) { | |
| 75 | _, | |
| 76 | ||
| 77 | pub fn uavValue(umi: UavMapIndex, coff: *const Coff) InternPool.Index { | |
| 78 | return coff.uavs.keys()[@intFromEnum(umi)]; | |
| 79 | } | |
| 80 | ||
| 81 | pub fn symbol(umi: UavMapIndex, coff: *const Coff) Symbol.Index { | |
| 82 | return coff.uavs.values()[@intFromEnum(umi)]; | |
| 83 | } | |
| 84 | }; | |
| 85 | ||
| 86 | pub const LazyMapRef = struct { | |
| 87 | kind: link.File.LazySymbol.Kind, | |
| 88 | index: u32, | |
| 89 | ||
| 90 | pub fn Index(comptime kind: link.File.LazySymbol.Kind) type { | |
| 91 | return enum(u32) { | |
| 92 | _, | |
| 93 | ||
| 94 | pub fn ref(lmi: @This()) LazyMapRef { | |
| 95 | return .{ .kind = kind, .index = @intFromEnum(lmi) }; | |
| 96 | } | |
| 97 | ||
| 98 | pub fn lazySymbol(lmi: @This(), coff: *const Coff) link.File.LazySymbol { | |
| 99 | return lmi.ref().lazySymbol(coff); | |
| 100 | } | |
| 101 | ||
| 102 | pub fn symbol(lmi: @This(), coff: *const Coff) Symbol.Index { | |
| 103 | return lmi.ref().symbol(coff); | |
| 104 | } | |
| 105 | }; | |
| 106 | } | |
| 107 | ||
| 108 | pub fn lazySymbol(lmr: LazyMapRef, coff: *const Coff) link.File.LazySymbol { | |
| 109 | return .{ .kind = lmr.kind, .ty = coff.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] }; | |
| 110 | } | |
| 111 | ||
| 112 | pub fn symbol(lmr: LazyMapRef, coff: *const Coff) Symbol.Index { | |
| 113 | return coff.lazy.getPtrConst(lmr.kind).map.values()[lmr.index]; | |
| 114 | } | |
| 115 | }; | |
| 116 | ||
| 117 | pub const Tag = @typeInfo(Node).@"union".tag_type.?; | |
| 118 | ||
| 119 | const known_count = @typeInfo(@TypeOf(known)).@"struct".fields.len; | |
| 120 | const known = known: { | |
| 121 | const Known = enum { | |
| 122 | file, | |
| 123 | header, | |
| 124 | signature, | |
| 125 | coff_header, | |
| 126 | optional_header, | |
| 127 | data_directories, | |
| 128 | section_table, | |
| 129 | }; | |
| 130 | var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined; | |
| 131 | for (@typeInfo(Known).@"enum".fields) |field| | |
| 132 | @field(mut_known, field.name) = @enumFromInt(field.value); | |
| 133 | break :known mut_known; | |
| 134 | }; | |
| 135 | ||
| 136 | comptime { | |
| 137 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8); | |
| 138 | } | |
| 139 | }; | |
| 140 | ||
| 141 | pub const DataDirectory = enum { | |
| 142 | export_table, | |
| 143 | import_table, | |
| 144 | resorce_table, | |
| 145 | exception_table, | |
| 146 | certificate_table, | |
| 147 | base_relocation_table, | |
| 148 | debug, | |
| 149 | architecture, | |
| 150 | global_ptr, | |
| 151 | tls_table, | |
| 152 | load_config_table, | |
| 153 | bound_import, | |
| 154 | import_address_table, | |
| 155 | delay_import_descriptor, | |
| 156 | clr_runtime_header, | |
| 157 | reserved, | |
| 158 | }; | |
| 159 | ||
| 160 | pub const ImportTable = struct { | |
| 161 | directory_table_ni: MappedFile.Node.Index, | |
| 162 | dlls: std.AutoArrayHashMapUnmanaged(void, Dll), | |
| 163 | ||
| 164 | pub const Dll = struct { | |
| 165 | import_lookup_table_ni: MappedFile.Node.Index, | |
| 166 | import_address_table_si: Symbol.Index, | |
| 167 | import_hint_name_table_ni: MappedFile.Node.Index, | |
| 168 | len: u32, | |
| 169 | hint_name_len: u32, | |
| 170 | }; | |
| 171 | ||
| 172 | const Adapter = struct { | |
| 173 | coff: *Coff, | |
| 174 | ||
| 175 | pub fn eql(adapter: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool { | |
| 176 | const coff = adapter.coff; | |
| 177 | const dll_name = coff.import_table.dlls.values()[rhs_index] | |
| 178 | .import_hint_name_table_ni.sliceConst(&coff.mf); | |
| 179 | return std.mem.startsWith(u8, dll_name, lhs_key) and | |
| 180 | std.mem.startsWith(u8, dll_name[lhs_key.len..], ".dll\x00"); | |
| 181 | } | |
| 182 | ||
| 183 | pub fn hash(_: Adapter, key: []const u8) u32 { | |
| 184 | assert(std.mem.indexOfScalar(u8, key, 0) == null); | |
| 185 | return std.array_hash_map.hashString(key); | |
| 186 | } | |
| 187 | }; | |
| 188 | }; | |
| 189 | ||
| 190 | pub const String = enum(u32) { | |
| 191 | _, | |
| 192 | ||
| 193 | pub const Optional = enum(u32) { | |
| 194 | none = std.math.maxInt(u32), | |
| 195 | _, | |
| 196 | ||
| 197 | pub fn unwrap(os: String.Optional) ?String { | |
| 198 | return switch (os) { | |
| 199 | else => |s| @enumFromInt(@intFromEnum(s)), | |
| 200 | .none => null, | |
| 201 | }; | |
| 202 | } | |
| 203 | ||
| 204 | pub fn toSlice(os: String.Optional, coff: *Coff) ?[:0]const u8 { | |
| 205 | return (os.unwrap() orelse return null).toSlice(coff); | |
| 206 | } | |
| 207 | }; | |
| 208 | ||
| 209 | pub fn toSlice(s: String, coff: *Coff) [:0]const u8 { | |
| 210 | const slice = coff.string_bytes.items[@intFromEnum(s)..]; | |
| 211 | return slice[0..std.mem.indexOfScalar(u8, slice, 0).? :0]; | |
| 212 | } | |
| 213 | ||
| 214 | pub fn toOptional(s: String) String.Optional { | |
| 215 | return @enumFromInt(@intFromEnum(s)); | |
| 216 | } | |
| 217 | }; | |
| 218 | ||
| 219 | pub const GlobalName = struct { name: String, lib_name: String.Optional }; | |
| 220 | ||
| 221 | pub const Symbol = struct { | |
| 222 | ni: MappedFile.Node.Index, | |
| 223 | rva: u32, | |
| 224 | size: u32, | |
| 225 | /// Relocations contained within this symbol | |
| 226 | loc_relocs: Reloc.Index, | |
| 227 | /// Relocations targeting this symbol | |
| 228 | target_relocs: Reloc.Index, | |
| 229 | section_number: SectionNumber, | |
| 230 | data_directory: ?DataDirectory, | |
| 231 | unused0: u32 = 0, | |
| 232 | unused1: u32 = 0, | |
| 233 | ||
| 234 | pub const SectionNumber = enum(i16) { | |
| 235 | UNDEFINED = 0, | |
| 236 | ABSOLUTE = -1, | |
| 237 | DEBUG = -2, | |
| 238 | _, | |
| 239 | ||
| 240 | fn toIndex(sn: SectionNumber) u15 { | |
| 241 | return @intCast(@intFromEnum(sn) - 1); | |
| 242 | } | |
| 243 | ||
| 244 | pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index { | |
| 245 | return coff.section_table.items[sn.toIndex()]; | |
| 246 | } | |
| 247 | ||
| 248 | pub fn header(sn: SectionNumber, coff: *Coff) *std.coff.SectionHeader { | |
| 249 | return &coff.sectionTableSlice()[sn.toIndex()]; | |
| 250 | } | |
| 251 | }; | |
| 252 | ||
| 253 | pub const Index = enum(u32) { | |
| 254 | null, | |
| 255 | data, | |
| 256 | idata, | |
| 257 | rdata, | |
| 258 | text, | |
| 259 | _, | |
| 260 | ||
| 261 | const known_count = @typeInfo(Index).@"enum".fields.len; | |
| 262 | ||
| 263 | pub fn get(si: Symbol.Index, coff: *Coff) *Symbol { | |
| 264 | return &coff.symbol_table.items[@intFromEnum(si)]; | |
| 265 | } | |
| 266 | ||
| 267 | pub fn node(si: Symbol.Index, coff: *Coff) MappedFile.Node.Index { | |
| 268 | const ni = si.get(coff).ni; | |
| 269 | assert(ni != .none); | |
| 270 | return ni; | |
| 271 | } | |
| 272 | ||
| 273 | pub fn flushMoved(si: Symbol.Index, coff: *Coff) void { | |
| 274 | const sym = si.get(coff); | |
| 275 | sym.rva = coff.computeNodeRva(sym.ni); | |
| 276 | if (si == coff.entry_hack) | |
| 277 | coff.targetStore(&coff.optionalHeaderStandardPtr().address_of_entry_point, sym.rva); | |
| 278 | si.applyLocationRelocs(coff); | |
| 279 | si.applyTargetRelocs(coff); | |
| 280 | } | |
| 281 | ||
| 282 | pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) void { | |
| 283 | for (coff.relocs.items[@intFromEnum(si.get(coff).loc_relocs)..]) |*reloc| { | |
| 284 | if (reloc.loc != si) break; | |
| 285 | reloc.apply(coff); | |
| 286 | } | |
| 287 | } | |
| 288 | ||
| 289 | pub fn applyTargetRelocs(si: Symbol.Index, coff: *Coff) void { | |
| 290 | var ri = si.get(coff).target_relocs; | |
| 291 | while (ri != .none) { | |
| 292 | const reloc = ri.get(coff); | |
| 293 | assert(reloc.target == si); | |
| 294 | reloc.apply(coff); | |
| 295 | ri = reloc.next; | |
| 296 | } | |
| 297 | } | |
| 298 | ||
| 299 | pub fn deleteLocationRelocs(si: Symbol.Index, coff: *Coff) void { | |
| 300 | const sym = si.get(coff); | |
| 301 | for (coff.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| { | |
| 302 | if (reloc.loc != si) break; | |
| 303 | reloc.delete(coff); | |
| 304 | } | |
| 305 | sym.loc_relocs = .none; | |
| 306 | } | |
| 307 | }; | |
| 308 | ||
| 309 | comptime { | |
| 310 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 32); | |
| 311 | } | |
| 312 | }; | |
| 313 | ||
| 314 | pub const Reloc = extern struct { | |
| 315 | type: Reloc.Type, | |
| 316 | prev: Reloc.Index, | |
| 317 | next: Reloc.Index, | |
| 318 | loc: Symbol.Index, | |
| 319 | target: Symbol.Index, | |
| 320 | unused: u32, | |
| 321 | offset: u64, | |
| 322 | addend: i64, | |
| 323 | ||
| 324 | pub const Type = extern union { | |
| 325 | AMD64: std.coff.IMAGE.REL.AMD64, | |
| 326 | ARM: std.coff.IMAGE.REL.ARM, | |
| 327 | ARM64: std.coff.IMAGE.REL.ARM64, | |
| 328 | SH: std.coff.IMAGE.REL.SH, | |
| 329 | PPC: std.coff.IMAGE.REL.PPC, | |
| 330 | I386: std.coff.IMAGE.REL.I386, | |
| 331 | IA64: std.coff.IMAGE.REL.IA64, | |
| 332 | MIPS: std.coff.IMAGE.REL.MIPS, | |
| 333 | M32R: std.coff.IMAGE.REL.M32R, | |
| 334 | }; | |
| 335 | ||
| 336 | pub const Index = enum(u32) { | |
| 337 | none = std.math.maxInt(u32), | |
| 338 | _, | |
| 339 | ||
| 340 | pub fn get(si: Reloc.Index, coff: *Coff) *Reloc { | |
| 341 | return &coff.relocs.items[@intFromEnum(si)]; | |
| 342 | } | |
| 343 | }; | |
| 344 | ||
| 345 | pub fn apply(reloc: *const Reloc, coff: *Coff) void { | |
| 346 | const loc_sym = reloc.loc.get(coff); | |
| 347 | switch (loc_sym.ni) { | |
| 348 | .none => return, | |
| 349 | else => |ni| if (ni.hasMoved(&coff.mf)) return, | |
| 350 | } | |
| 351 | const target_sym = reloc.target.get(coff); | |
| 352 | switch (target_sym.ni) { | |
| 353 | .none => return, | |
| 354 | else => |ni| if (ni.hasMoved(&coff.mf)) return, | |
| 355 | } | |
| 356 | const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..]; | |
| 357 | const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend)); | |
| 358 | const target_endian = coff.targetEndian(); | |
| 359 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | |
| 360 | else => |machine| @panic(@tagName(machine)), | |
| 361 | .AMD64 => switch (reloc.type.AMD64) { | |
| 362 | else => |kind| @panic(@tagName(kind)), | |
| 363 | .ABSOLUTE => {}, | |
| 364 | .ADDR64 => std.mem.writeInt( | |
| 365 | u64, | |
| 366 | loc_slice[0..8], | |
| 367 | coff.optionalHeaderField(.image_base) + target_rva, | |
| 368 | target_endian, | |
| 369 | ), | |
| 370 | .ADDR32 => std.mem.writeInt( | |
| 371 | u32, | |
| 372 | loc_slice[0..4], | |
| 373 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | |
| 374 | target_endian, | |
| 375 | ), | |
| 376 | .ADDR32NB => std.mem.writeInt( | |
| 377 | u32, | |
| 378 | loc_slice[0..4], | |
| 379 | @intCast(target_rva), | |
| 380 | target_endian, | |
| 381 | ), | |
| 382 | .REL32 => std.mem.writeInt( | |
| 383 | i32, | |
| 384 | loc_slice[0..4], | |
| 385 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))), | |
| 386 | target_endian, | |
| 387 | ), | |
| 388 | .REL32_1 => std.mem.writeInt( | |
| 389 | i32, | |
| 390 | loc_slice[0..4], | |
| 391 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 5)))), | |
| 392 | target_endian, | |
| 393 | ), | |
| 394 | .REL32_2 => std.mem.writeInt( | |
| 395 | i32, | |
| 396 | loc_slice[0..4], | |
| 397 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 6)))), | |
| 398 | target_endian, | |
| 399 | ), | |
| 400 | .REL32_3 => std.mem.writeInt( | |
| 401 | i32, | |
| 402 | loc_slice[0..4], | |
| 403 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 7)))), | |
| 404 | target_endian, | |
| 405 | ), | |
| 406 | .REL32_4 => std.mem.writeInt( | |
| 407 | i32, | |
| 408 | loc_slice[0..4], | |
| 409 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 8)))), | |
| 410 | target_endian, | |
| 411 | ), | |
| 412 | .REL32_5 => std.mem.writeInt( | |
| 413 | i32, | |
| 414 | loc_slice[0..4], | |
| 415 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))), | |
| 416 | target_endian, | |
| 417 | ), | |
| 418 | }, | |
| 419 | .I386 => switch (reloc.type.I386) { | |
| 420 | else => |kind| @panic(@tagName(kind)), | |
| 421 | .ABSOLUTE => {}, | |
| 422 | .DIR16 => std.mem.writeInt( | |
| 423 | u16, | |
| 424 | loc_slice[0..2], | |
| 425 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | |
| 426 | target_endian, | |
| 427 | ), | |
| 428 | .REL16 => std.mem.writeInt( | |
| 429 | i16, | |
| 430 | loc_slice[0..2], | |
| 431 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 2)))), | |
| 432 | target_endian, | |
| 433 | ), | |
| 434 | .DIR32 => std.mem.writeInt( | |
| 435 | u32, | |
| 436 | loc_slice[0..4], | |
| 437 | @intCast(coff.optionalHeaderField(.image_base) + target_rva), | |
| 438 | target_endian, | |
| 439 | ), | |
| 440 | .DIR32NB => std.mem.writeInt( | |
| 441 | u32, | |
| 442 | loc_slice[0..4], | |
| 443 | @intCast(target_rva), | |
| 444 | target_endian, | |
| 445 | ), | |
| 446 | .REL32 => std.mem.writeInt( | |
| 447 | i32, | |
| 448 | loc_slice[0..4], | |
| 449 | @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))), | |
| 450 | target_endian, | |
| 451 | ), | |
| 452 | }, | |
| 453 | } | |
| 454 | } | |
| 455 | ||
| 456 | pub fn delete(reloc: *Reloc, coff: *Coff) void { | |
| 457 | switch (reloc.prev) { | |
| 458 | .none => { | |
| 459 | const target = reloc.target.get(coff); | |
| 460 | assert(target.target_relocs.get(coff) == reloc); | |
| 461 | target.target_relocs = reloc.next; | |
| 462 | }, | |
| 463 | else => |prev| prev.get(coff).next = reloc.next, | |
| 464 | } | |
| 465 | switch (reloc.next) { | |
| 466 | .none => {}, | |
| 467 | else => |next| next.get(coff).prev = reloc.prev, | |
| 468 | } | |
| 469 | reloc.* = undefined; | |
| 470 | } | |
| 471 | ||
| 472 | comptime { | |
| 473 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40); | |
| 474 | } | |
| 475 | }; | |
| 476 | ||
| 477 | pub fn open( | |
| 478 | arena: std.mem.Allocator, | |
| 479 | comp: *Compilation, | |
| 480 | path: std.Build.Cache.Path, | |
| 481 | options: link.File.OpenOptions, | |
| 482 | ) !*Coff { | |
| 483 | return create(arena, comp, path, options); | |
| 484 | } | |
| 485 | pub fn createEmpty( | |
| 486 | arena: std.mem.Allocator, | |
| 487 | comp: *Compilation, | |
| 488 | path: std.Build.Cache.Path, | |
| 489 | options: link.File.OpenOptions, | |
| 490 | ) !*Coff { | |
| 491 | return create(arena, comp, path, options); | |
| 492 | } | |
| 493 | fn create( | |
| 494 | arena: std.mem.Allocator, | |
| 495 | comp: *Compilation, | |
| 496 | path: std.Build.Cache.Path, | |
| 497 | options: link.File.OpenOptions, | |
| 498 | ) !*Coff { | |
| 499 | const target = &comp.root_mod.resolved_target.result; | |
| 500 | assert(target.ofmt == .coff); | |
| 501 | const is_image = switch (comp.config.output_mode) { | |
| 502 | .Exe => true, | |
| 503 | .Lib => switch (comp.config.link_mode) { | |
| 504 | .static => false, | |
| 505 | .dynamic => true, | |
| 506 | }, | |
| 507 | .Obj => false, | |
| 508 | }; | |
| 509 | const machine = target.toCoffMachine(); | |
| 510 | const timestamp: u32 = if (options.repro) 0 else @truncate(@as(u64, @bitCast(std.time.timestamp()))); | |
| 511 | const major_subsystem_version = options.major_subsystem_version orelse 6; | |
| 512 | const minor_subsystem_version = options.minor_subsystem_version orelse 0; | |
| 513 | const magic: std.coff.OptionalHeader.Magic = switch (target.ptrBitWidth()) { | |
| 514 | 0...32 => .PE32, | |
| 515 | 33...64 => .@"PE32+", | |
| 516 | else => return error.UnsupportedCOFFArchitecture, | |
| 517 | }; | |
| 518 | const section_align: std.mem.Alignment = switch (machine) { | |
| 519 | .AMD64, .I386 => @enumFromInt(12), | |
| 520 | .SH3, .SH3DSP, .SH4, .SH5 => @enumFromInt(12), | |
| 521 | .MIPS16, .MIPSFPU, .MIPSFPU16, .WCEMIPSV2 => @enumFromInt(12), | |
| 522 | .POWERPC, .POWERPCFP => @enumFromInt(12), | |
| 523 | .ALPHA, .ALPHA64 => @enumFromInt(13), | |
| 524 | .IA64 => @enumFromInt(13), | |
| 525 | .ARM => @enumFromInt(12), | |
| 526 | else => return error.UnsupportedCOFFArchitecture, | |
| 527 | }; | |
| 528 | ||
| 529 | const coff = try arena.create(Coff); | |
| 530 | const file = try path.root_dir.handle.createFile(path.sub_path, .{ | |
| 531 | .read = true, | |
| 532 | .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode), | |
| 533 | }); | |
| 534 | errdefer file.close(); | |
| 535 | coff.* = .{ | |
| 536 | .base = .{ | |
| 537 | .tag = .coff2, | |
| 538 | ||
| 539 | .comp = comp, | |
| 540 | .emit = path, | |
| 541 | ||
| 542 | .file = file, | |
| 543 | .gc_sections = false, | |
| 544 | .print_gc_sections = false, | |
| 545 | .build_id = .none, | |
| 546 | .allow_shlib_undefined = false, | |
| 547 | .stack_size = 0, | |
| 548 | }, | |
| 549 | .endian = target.cpu.arch.endian(), | |
| 550 | .mf = try .init(file, comp.gpa), | |
| 551 | .nodes = .empty, | |
| 552 | .import_table = .{ | |
| 553 | .directory_table_ni = .none, | |
| 554 | .dlls = .empty, | |
| 555 | }, | |
| 556 | .strings = .empty, | |
| 557 | .string_bytes = .empty, | |
| 558 | .section_table = .empty, | |
| 559 | .symbol_table = .empty, | |
| 560 | .globals = .empty, | |
| 561 | .global_pending_index = 0, | |
| 562 | .navs = .empty, | |
| 563 | .uavs = .empty, | |
| 564 | .lazy = .initFill(.{ | |
| 565 | .map = .empty, | |
| 566 | .pending_index = 0, | |
| 567 | }), | |
| 568 | .pending_uavs = .empty, | |
| 569 | .relocs = .empty, | |
| 570 | .entry_hack = .null, | |
| 571 | }; | |
| 572 | errdefer coff.deinit(); | |
| 573 | ||
| 574 | try coff.initHeaders( | |
| 575 | is_image, | |
| 576 | machine, | |
| 577 | timestamp, | |
| 578 | major_subsystem_version, | |
| 579 | minor_subsystem_version, | |
| 580 | magic, | |
| 581 | section_align, | |
| 582 | ); | |
| 583 | return coff; | |
| 584 | } | |
| 585 | ||
| 586 | pub fn deinit(coff: *Coff) void { | |
| 587 | const gpa = coff.base.comp.gpa; | |
| 588 | coff.mf.deinit(gpa); | |
| 589 | coff.nodes.deinit(gpa); | |
| 590 | coff.import_table.dlls.deinit(gpa); | |
| 591 | coff.strings.deinit(gpa); | |
| 592 | coff.string_bytes.deinit(gpa); | |
| 593 | coff.section_table.deinit(gpa); | |
| 594 | coff.symbol_table.deinit(gpa); | |
| 595 | coff.globals.deinit(gpa); | |
| 596 | coff.navs.deinit(gpa); | |
| 597 | coff.uavs.deinit(gpa); | |
| 598 | for (&coff.lazy.values) |*lazy| lazy.map.deinit(gpa); | |
| 599 | coff.pending_uavs.deinit(gpa); | |
| 600 | coff.relocs.deinit(gpa); | |
| 601 | coff.* = undefined; | |
| 602 | } | |
| 603 | ||
| 604 | fn initHeaders( | |
| 605 | coff: *Coff, | |
| 606 | is_image: bool, | |
| 607 | machine: std.coff.IMAGE.FILE.MACHINE, | |
| 608 | timestamp: u32, | |
| 609 | major_subsystem_version: u16, | |
| 610 | minor_subsystem_version: u16, | |
| 611 | magic: std.coff.OptionalHeader.Magic, | |
| 612 | section_align: std.mem.Alignment, | |
| 613 | ) !void { | |
| 614 | const comp = coff.base.comp; | |
| 615 | const gpa = comp.gpa; | |
| 616 | const file_align: std.mem.Alignment = | |
| 617 | comptime .fromByteUnits(link.File.Coff.default_file_alignment); | |
| 618 | const target_endian = coff.targetEndian(); | |
| 619 | ||
| 620 | const optional_header_size: u16 = if (is_image) switch (magic) { | |
| 621 | _ => unreachable, | |
| 622 | inline else => |ct_magic| @sizeOf(@field(std.coff.OptionalHeader, @tagName(ct_magic))), | |
| 623 | } else 0; | |
| 624 | const data_directories_len = @typeInfo(DataDirectory).@"enum".fields.len; | |
| 625 | const data_directories_size: u16 = if (is_image) | |
| 626 | @sizeOf(std.coff.ImageDataDirectory) * data_directories_len | |
| 627 | else | |
| 628 | 0; | |
| 629 | ||
| 630 | try coff.nodes.ensureTotalCapacity(gpa, Node.known_count); | |
| 631 | coff.nodes.appendAssumeCapacity(.file); | |
| 632 | ||
| 633 | const header_ni = Node.known.header; | |
| 634 | assert(header_ni == try coff.mf.addOnlyChildNode(gpa, .root, .{ | |
| 635 | .alignment = coff.mf.flags.block_size, | |
| 636 | .fixed = true, | |
| 637 | })); | |
| 638 | coff.nodes.appendAssumeCapacity(.header); | |
| 639 | ||
| 640 | const signature_ni = Node.known.signature; | |
| 641 | assert(signature_ni == try coff.mf.addOnlyChildNode(gpa, header_ni, .{ | |
| 642 | .size = (if (is_image) link.File.Coff.msdos_stub.len else 0) + "PE\x00\x00".len, | |
| 643 | .alignment = .@"4", | |
| 644 | .fixed = true, | |
| 645 | })); | |
| 646 | coff.nodes.appendAssumeCapacity(.signature); | |
| 647 | { | |
| 648 | const signature_slice = signature_ni.slice(&coff.mf); | |
| 649 | if (is_image) | |
| 650 | @memcpy(signature_slice[0..link.File.Coff.msdos_stub.len], &link.File.Coff.msdos_stub); | |
| 651 | @memcpy(signature_slice[signature_slice.len - 4 ..], "PE\x00\x00"); | |
| 652 | } | |
| 653 | ||
| 654 | const coff_header_ni = Node.known.coff_header; | |
| 655 | assert(coff_header_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | |
| 656 | .size = @sizeOf(std.coff.Header), | |
| 657 | .alignment = .@"4", | |
| 658 | .fixed = true, | |
| 659 | })); | |
| 660 | coff.nodes.appendAssumeCapacity(.coff_header); | |
| 661 | { | |
| 662 | const coff_header: *std.coff.Header = @ptrCast(@alignCast(coff_header_ni.slice(&coff.mf))); | |
| 663 | coff_header.* = .{ | |
| 664 | .machine = machine, | |
| 665 | .number_of_sections = 0, | |
| 666 | .time_date_stamp = timestamp, | |
| 667 | .pointer_to_symbol_table = 0, | |
| 668 | .number_of_symbols = 0, | |
| 669 | .size_of_optional_header = optional_header_size + data_directories_size, | |
| 670 | .flags = .{ | |
| 671 | .RELOCS_STRIPPED = is_image, | |
| 672 | .EXECUTABLE_IMAGE = is_image, | |
| 673 | .DEBUG_STRIPPED = true, | |
| 674 | .@"32BIT_MACHINE" = magic == .PE32, | |
| 675 | .LARGE_ADDRESS_AWARE = magic == .@"PE32+", | |
| 676 | .DLL = comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic, | |
| 677 | }, | |
| 678 | }; | |
| 679 | if (target_endian != native_endian) std.mem.byteSwapAllFields(std.coff.Header, coff_header); | |
| 680 | } | |
| 681 | ||
| 682 | const optional_header_ni = Node.known.optional_header; | |
| 683 | assert(optional_header_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | |
| 684 | .size = optional_header_size, | |
| 685 | .alignment = .@"4", | |
| 686 | .fixed = true, | |
| 687 | })); | |
| 688 | coff.nodes.appendAssumeCapacity(.optional_header); | |
| 689 | if (is_image) switch (magic) { | |
| 690 | _ => unreachable, | |
| 691 | .PE32 => { | |
| 692 | const optional_header: *std.coff.OptionalHeader.PE32 = | |
| 693 | @ptrCast(@alignCast(optional_header_ni.slice(&coff.mf))); | |
| 694 | optional_header.* = .{ | |
| 695 | .standard = .{ | |
| 696 | .magic = .PE32, | |
| 697 | .major_linker_version = 0, | |
| 698 | .minor_linker_version = 0, | |
| 699 | .size_of_code = 0, | |
| 700 | .size_of_initialized_data = 0, | |
| 701 | .size_of_uninitialized_data = 0, | |
| 702 | .address_of_entry_point = 0, | |
| 703 | .base_of_code = 0, | |
| 704 | }, | |
| 705 | .base_of_data = 0, | |
| 706 | .image_base = switch (coff.base.comp.config.output_mode) { | |
| 707 | .Exe => 0x400000, | |
| 708 | .Lib => switch (coff.base.comp.config.link_mode) { | |
| 709 | .static => 0, | |
| 710 | .dynamic => 0x10000000, | |
| 711 | }, | |
| 712 | .Obj => 0, | |
| 713 | }, | |
| 714 | .section_alignment = @intCast(section_align.toByteUnits()), | |
| 715 | .file_alignment = @intCast(file_align.toByteUnits()), | |
| 716 | .major_operating_system_version = 6, | |
| 717 | .minor_operating_system_version = 0, | |
| 718 | .major_image_version = 0, | |
| 719 | .minor_image_version = 0, | |
| 720 | .major_subsystem_version = major_subsystem_version, | |
| 721 | .minor_subsystem_version = minor_subsystem_version, | |
| 722 | .win32_version_value = 0, | |
| 723 | .size_of_image = 0, | |
| 724 | .size_of_headers = 0, | |
| 725 | .checksum = 0, | |
| 726 | .subsystem = .WINDOWS_CUI, | |
| 727 | .dll_flags = .{ | |
| 728 | .HIGH_ENTROPY_VA = true, | |
| 729 | .DYNAMIC_BASE = true, | |
| 730 | .TERMINAL_SERVER_AWARE = true, | |
| 731 | .NX_COMPAT = true, | |
| 732 | }, | |
| 733 | .size_of_stack_reserve = link.File.Coff.default_size_of_stack_reserve, | |
| 734 | .size_of_stack_commit = link.File.Coff.default_size_of_stack_commit, | |
| 735 | .size_of_heap_reserve = link.File.Coff.default_size_of_heap_reserve, | |
| 736 | .size_of_heap_commit = link.File.Coff.default_size_of_heap_commit, | |
| 737 | .loader_flags = 0, | |
| 738 | .number_of_rva_and_sizes = data_directories_len, | |
| 739 | }; | |
| 740 | if (target_endian != native_endian) | |
| 741 | std.mem.byteSwapAllFields(std.coff.OptionalHeader.PE32, optional_header); | |
| 742 | }, | |
| 743 | .@"PE32+" => { | |
| 744 | const header: *std.coff.OptionalHeader.@"PE32+" = | |
| 745 | @ptrCast(@alignCast(optional_header_ni.slice(&coff.mf))); | |
| 746 | header.* = .{ | |
| 747 | .standard = .{ | |
| 748 | .magic = .@"PE32+", | |
| 749 | .major_linker_version = 0, | |
| 750 | .minor_linker_version = 0, | |
| 751 | .size_of_code = 0, | |
| 752 | .size_of_initialized_data = 0, | |
| 753 | .size_of_uninitialized_data = 0, | |
| 754 | .address_of_entry_point = 0, | |
| 755 | .base_of_code = 0, | |
| 756 | }, | |
| 757 | .image_base = switch (coff.base.comp.config.output_mode) { | |
| 758 | .Exe => 0x140000000, | |
| 759 | .Lib => switch (coff.base.comp.config.link_mode) { | |
| 760 | .static => 0, | |
| 761 | .dynamic => 0x180000000, | |
| 762 | }, | |
| 763 | .Obj => 0, | |
| 764 | }, | |
| 765 | .section_alignment = @intCast(section_align.toByteUnits()), | |
| 766 | .file_alignment = @intCast(file_align.toByteUnits()), | |
| 767 | .major_operating_system_version = 6, | |
| 768 | .minor_operating_system_version = 0, | |
| 769 | .major_image_version = 0, | |
| 770 | .minor_image_version = 0, | |
| 771 | .major_subsystem_version = major_subsystem_version, | |
| 772 | .minor_subsystem_version = minor_subsystem_version, | |
| 773 | .win32_version_value = 0, | |
| 774 | .size_of_image = 0, | |
| 775 | .size_of_headers = 0, | |
| 776 | .checksum = 0, | |
| 777 | .subsystem = .WINDOWS_CUI, | |
| 778 | .dll_flags = .{ | |
| 779 | .HIGH_ENTROPY_VA = true, | |
| 780 | .DYNAMIC_BASE = true, | |
| 781 | .TERMINAL_SERVER_AWARE = true, | |
| 782 | .NX_COMPAT = true, | |
| 783 | }, | |
| 784 | .size_of_stack_reserve = link.File.Coff.default_size_of_stack_reserve, | |
| 785 | .size_of_stack_commit = link.File.Coff.default_size_of_stack_commit, | |
| 786 | .size_of_heap_reserve = link.File.Coff.default_size_of_heap_reserve, | |
| 787 | .size_of_heap_commit = link.File.Coff.default_size_of_heap_commit, | |
| 788 | .loader_flags = 0, | |
| 789 | .number_of_rva_and_sizes = data_directories_len, | |
| 790 | }; | |
| 791 | if (target_endian != native_endian) | |
| 792 | std.mem.byteSwapAllFields(std.coff.OptionalHeader.@"PE32+", header); | |
| 793 | }, | |
| 794 | }; | |
| 795 | ||
| 796 | const data_directories_ni = Node.known.data_directories; | |
| 797 | assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | |
| 798 | .size = data_directories_size, | |
| 799 | .alignment = .@"4", | |
| 800 | .fixed = true, | |
| 801 | })); | |
| 802 | coff.nodes.appendAssumeCapacity(.data_directories); | |
| 803 | { | |
| 804 | const data_directories: *[data_directories_len]std.coff.ImageDataDirectory = | |
| 805 | @ptrCast(@alignCast(data_directories_ni.slice(&coff.mf))); | |
| 806 | @memset(data_directories, .{ .virtual_address = 0, .size = 0 }); | |
| 807 | if (target_endian != native_endian) for (data_directories) |*data_directory| | |
| 808 | std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, data_directory); | |
| 809 | } | |
| 810 | ||
| 811 | const section_table_ni = Node.known.section_table; | |
| 812 | assert(section_table_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ | |
| 813 | .alignment = .@"4", | |
| 814 | .fixed = true, | |
| 815 | })); | |
| 816 | coff.nodes.appendAssumeCapacity(.section_table); | |
| 817 | ||
| 818 | assert(coff.nodes.len == Node.known_count); | |
| 819 | ||
| 820 | try coff.symbol_table.ensureTotalCapacity(gpa, Symbol.Index.known_count); | |
| 821 | coff.symbol_table.addOneAssumeCapacity().* = .{ | |
| 822 | .ni = .none, | |
| 823 | .rva = 0, | |
| 824 | .size = 0, | |
| 825 | .loc_relocs = .none, | |
| 826 | .target_relocs = .none, | |
| 827 | .section_number = .UNDEFINED, | |
| 828 | .data_directory = null, | |
| 829 | }; | |
| 830 | assert(try coff.addSection(".data", null, .{ | |
| 831 | .CNT_INITIALIZED_DATA = true, | |
| 832 | .MEM_READ = true, | |
| 833 | .MEM_WRITE = true, | |
| 834 | }) == .data); | |
| 835 | assert(try coff.addSection(".idata", .import_table, .{ | |
| 836 | .CNT_INITIALIZED_DATA = true, | |
| 837 | .MEM_READ = true, | |
| 838 | }) == .idata); | |
| 839 | assert(try coff.addSection(".rdata", null, .{ | |
| 840 | .CNT_INITIALIZED_DATA = true, | |
| 841 | .MEM_READ = true, | |
| 842 | }) == .rdata); | |
| 843 | assert(try coff.addSection(".text", null, .{ | |
| 844 | .CNT_CODE = true, | |
| 845 | .MEM_EXECUTE = true, | |
| 846 | .MEM_READ = true, | |
| 847 | }) == .text); | |
| 848 | coff.import_table.directory_table_ni = try coff.mf.addLastChildNode( | |
| 849 | gpa, | |
| 850 | Symbol.Index.idata.node(coff), | |
| 851 | .{ | |
| 852 | .alignment = .@"4", | |
| 853 | .fixed = true, | |
| 854 | }, | |
| 855 | ); | |
| 856 | coff.nodes.appendAssumeCapacity(.import_directory_table); | |
| 857 | assert(coff.symbol_table.items.len == Symbol.Index.known_count); | |
| 858 | } | |
| 859 | ||
| 860 | fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node { | |
| 861 | return coff.nodes.get(@intFromEnum(ni)); | |
| 862 | } | |
| 863 | fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { | |
| 864 | var section_offset: u32 = 0; | |
| 865 | var parent_ni = ni; | |
| 866 | while (true) { | |
| 867 | assert(parent_ni != .none); | |
| 868 | switch (coff.getNode(parent_ni)) { | |
| 869 | else => {}, | |
| 870 | .section => |si| return si.get(coff).rva + section_offset, | |
| 871 | } | |
| 872 | const parent_offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf); | |
| 873 | section_offset += @intCast(parent_offset); | |
| 874 | parent_ni = parent_ni.parent(&coff.mf); | |
| 875 | } | |
| 876 | } | |
| 877 | ||
| 878 | pub inline fn targetEndian(coff: *const Coff) std.builtin.Endian { | |
| 879 | return coff.endian; | |
| 880 | } | |
| 881 | fn targetLoad(coff: *const Coff, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child { | |
| 882 | const Child = @typeInfo(@TypeOf(ptr)).pointer.child; | |
| 883 | return switch (@typeInfo(Child)) { | |
| 884 | else => @compileError(@typeName(Child)), | |
| 885 | .int => std.mem.toNative(Child, ptr.*, coff.targetEndian()), | |
| 886 | .@"enum" => |@"enum"| @enumFromInt(coff.targetLoad(@as(*@"enum".tag_type, @ptrCast(ptr)))), | |
| 887 | .@"struct" => |@"struct"| @bitCast( | |
| 888 | coff.targetLoad(@as(*@"struct".backing_integer.?, @ptrCast(ptr))), | |
| 889 | ), | |
| 890 | }; | |
| 891 | } | |
| 892 | fn targetStore(coff: *const Coff, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).pointer.child) void { | |
| 893 | const Child = @typeInfo(@TypeOf(ptr)).pointer.child; | |
| 894 | return switch (@typeInfo(Child)) { | |
| 895 | else => @compileError(@typeName(Child)), | |
| 896 | .int => ptr.* = std.mem.nativeTo(Child, val, coff.targetEndian()), | |
| 897 | .@"enum" => |@"enum"| coff.targetStore( | |
| 898 | @as(*@"enum".tag_type, @ptrCast(ptr)), | |
| 899 | @intFromEnum(val), | |
| 900 | ), | |
| 901 | .@"struct" => |@"struct"| coff.targetStore( | |
| 902 | @as(*@"struct".backing_integer.?, @ptrCast(ptr)), | |
| 903 | @bitCast(val), | |
| 904 | ), | |
| 905 | }; | |
| 906 | } | |
| 907 | ||
| 908 | pub fn headerPtr(coff: *Coff) *std.coff.Header { | |
| 909 | return @ptrCast(@alignCast(Node.known.coff_header.slice(&coff.mf))); | |
| 910 | } | |
| 911 | ||
| 912 | pub fn optionalHeaderStandardPtr(coff: *Coff) *std.coff.OptionalHeader { | |
| 913 | return @ptrCast(@alignCast( | |
| 914 | Node.known.optional_header.slice(&coff.mf)[0..@sizeOf(std.coff.OptionalHeader)], | |
| 915 | )); | |
| 916 | } | |
| 917 | ||
| 918 | pub const OptionalHeaderPtr = union(std.coff.OptionalHeader.Magic) { | |
| 919 | PE32: *std.coff.OptionalHeader.PE32, | |
| 920 | @"PE32+": *std.coff.OptionalHeader.@"PE32+", | |
| 921 | }; | |
| 922 | pub fn optionalHeaderPtr(coff: *Coff) OptionalHeaderPtr { | |
| 923 | const slice = Node.known.optional_header.slice(&coff.mf); | |
| 924 | return switch (coff.targetLoad(&coff.optionalHeaderStandardPtr().magic)) { | |
| 925 | _ => unreachable, | |
| 926 | inline else => |magic| @unionInit( | |
| 927 | OptionalHeaderPtr, | |
| 928 | @tagName(magic), | |
| 929 | @ptrCast(@alignCast(slice)), | |
| 930 | ), | |
| 931 | }; | |
| 932 | } | |
| 933 | pub fn optionalHeaderField( | |
| 934 | coff: *Coff, | |
| 935 | comptime field: std.meta.FieldEnum(std.coff.OptionalHeader.@"PE32+"), | |
| 936 | ) @FieldType(std.coff.OptionalHeader.@"PE32+", @tagName(field)) { | |
| 937 | return switch (coff.optionalHeaderPtr()) { | |
| 938 | inline else => |optional_header| coff.targetLoad(&@field(optional_header, @tagName(field))), | |
| 939 | }; | |
| 940 | } | |
| 941 | ||
| 942 | pub fn dataDirectoriesSlice(coff: *Coff) []std.coff.ImageDataDirectory { | |
| 943 | return @ptrCast(@alignCast(Node.known.data_directories.slice(&coff.mf))); | |
| 944 | } | |
| 945 | ||
| 946 | pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader { | |
| 947 | return @ptrCast(@alignCast(Node.known.section_table.slice(&coff.mf))); | |
| 948 | } | |
| 949 | ||
| 950 | fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index { | |
| 951 | defer coff.symbol_table.addOneAssumeCapacity().* = .{ | |
| 952 | .ni = .none, | |
| 953 | .rva = 0, | |
| 954 | .size = 0, | |
| 955 | .loc_relocs = .none, | |
| 956 | .target_relocs = .none, | |
| 957 | .section_number = .UNDEFINED, | |
| 958 | .data_directory = null, | |
| 959 | }; | |
| 960 | return @enumFromInt(coff.symbol_table.items.len); | |
| 961 | } | |
| 962 | ||
| 963 | fn initSymbolAssumeCapacity(coff: *Coff) !Symbol.Index { | |
| 964 | const si = coff.addSymbolAssumeCapacity(); | |
| 965 | return si; | |
| 966 | } | |
| 967 | ||
| 968 | fn getOrPutString(coff: *Coff, string: []const u8) !String { | |
| 969 | const gpa = coff.base.comp.gpa; | |
| 970 | try coff.string_bytes.ensureUnusedCapacity(gpa, string.len + 1); | |
| 971 | const gop = try coff.strings.getOrPutContextAdapted( | |
| 972 | gpa, | |
| 973 | string, | |
| 974 | std.hash_map.StringIndexAdapter{ .bytes = &coff.string_bytes }, | |
| 975 | .{ .bytes = &coff.string_bytes }, | |
| 976 | ); | |
| 977 | if (!gop.found_existing) { | |
| 978 | gop.key_ptr.* = @intCast(coff.string_bytes.items.len); | |
| 979 | gop.value_ptr.* = {}; | |
| 980 | coff.string_bytes.appendSliceAssumeCapacity(string); | |
| 981 | coff.string_bytes.appendAssumeCapacity(0); | |
| 982 | } | |
| 983 | return @enumFromInt(gop.key_ptr.*); | |
| 984 | } | |
| 985 | ||
| 986 | fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional { | |
| 987 | return (try coff.getOrPutString(string orelse return .none)).toOptional(); | |
| 988 | } | |
| 989 | ||
| 990 | pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { | |
| 991 | const gpa = coff.base.comp.gpa; | |
| 992 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | |
| 993 | const sym_gop = try coff.globals.getOrPut(gpa, .{ | |
| 994 | .name = try coff.getOrPutString(name), | |
| 995 | .lib_name = try coff.getOrPutOptionalString(lib_name), | |
| 996 | }); | |
| 997 | if (!sym_gop.found_existing) { | |
| 998 | sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); | |
| 999 | coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1); | |
| 1000 | } | |
| 1001 | return sym_gop.value_ptr.*; | |
| 1002 | } | |
| 1003 | ||
| 1004 | fn navMapIndex(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { | |
| 1005 | const gpa = zcu.gpa; | |
| 1006 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | |
| 1007 | const sym_gop = try coff.navs.getOrPut(gpa, nav_index); | |
| 1008 | if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); | |
| 1009 | return @enumFromInt(sym_gop.index); | |
| 1010 | } | |
| 1011 | pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { | |
| 1012 | const ip = &zcu.intern_pool; | |
| 1013 | const nav = ip.getNav(nav_index); | |
| 1014 | if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol( | |
| 1015 | @"extern".name.toSlice(ip), | |
| 1016 | @"extern".lib_name.toSlice(ip), | |
| 1017 | ); | |
| 1018 | const nmi = try coff.navMapIndex(zcu, nav_index); | |
| 1019 | return nmi.symbol(coff); | |
| 1020 | } | |
| 1021 | ||
| 1022 | fn uavMapIndex(coff: *Coff, uav_val: InternPool.Index) !Node.UavMapIndex { | |
| 1023 | const gpa = coff.base.comp.gpa; | |
| 1024 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | |
| 1025 | const sym_gop = try coff.uavs.getOrPut(gpa, uav_val); | |
| 1026 | if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); | |
| 1027 | return @enumFromInt(sym_gop.index); | |
| 1028 | } | |
| 1029 | pub fn uavSymbol(coff: *Coff, uav_val: InternPool.Index) !Symbol.Index { | |
| 1030 | const umi = try coff.uavMapIndex(uav_val); | |
| 1031 | return umi.symbol(coff); | |
| 1032 | } | |
| 1033 | ||
| 1034 | pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index { | |
| 1035 | const gpa = coff.base.comp.gpa; | |
| 1036 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | |
| 1037 | const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); | |
| 1038 | if (!sym_gop.found_existing) { | |
| 1039 | sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity(); | |
| 1040 | coff.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1); | |
| 1041 | } | |
| 1042 | return sym_gop.value_ptr.*; | |
| 1043 | } | |
| 1044 | ||
| 1045 | pub fn getNavVAddr( | |
| 1046 | coff: *Coff, | |
| 1047 | pt: Zcu.PerThread, | |
| 1048 | nav: InternPool.Nav.Index, | |
| 1049 | reloc_info: link.File.RelocInfo, | |
| 1050 | ) !u64 { | |
| 1051 | return coff.getVAddr(reloc_info, try coff.navSymbol(pt.zcu, nav)); | |
| 1052 | } | |
| 1053 | ||
| 1054 | pub fn getUavVAddr( | |
| 1055 | coff: *Coff, | |
| 1056 | uav: InternPool.Index, | |
| 1057 | reloc_info: link.File.RelocInfo, | |
| 1058 | ) !u64 { | |
| 1059 | return coff.getVAddr(reloc_info, try coff.uavSymbol(uav)); | |
| 1060 | } | |
| 1061 | ||
| 1062 | pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 { | |
| 1063 | try coff.addReloc( | |
| 1064 | @enumFromInt(reloc_info.parent.atom_index), | |
| 1065 | reloc_info.offset, | |
| 1066 | target_si, | |
| 1067 | reloc_info.addend, | |
| 1068 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | |
| 1069 | else => unreachable, | |
| 1070 | .AMD64 => .{ .AMD64 = .ADDR64 }, | |
| 1071 | .I386 => .{ .I386 = .DIR32 }, | |
| 1072 | }, | |
| 1073 | ); | |
| 1074 | return coff.optionalHeaderField(.image_base) + target_si.get(coff).rva; | |
| 1075 | } | |
| 1076 | ||
| 1077 | fn addSection( | |
| 1078 | coff: *Coff, | |
| 1079 | name: []const u8, | |
| 1080 | maybe_data_directory: ?DataDirectory, | |
| 1081 | flags: std.coff.SectionHeader.Flags, | |
| 1082 | ) !Symbol.Index { | |
| 1083 | const gpa = coff.base.comp.gpa; | |
| 1084 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | |
| 1085 | try coff.section_table.ensureUnusedCapacity(gpa, 1); | |
| 1086 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | |
| 1087 | ||
| 1088 | const coff_header = coff.headerPtr(); | |
| 1089 | const section_index = coff.targetLoad(&coff_header.number_of_sections); | |
| 1090 | const section_table_len = section_index + 1; | |
| 1091 | coff.targetStore(&coff_header.number_of_sections, section_table_len); | |
| 1092 | try Node.known.section_table.resize( | |
| 1093 | &coff.mf, | |
| 1094 | gpa, | |
| 1095 | @sizeOf(std.coff.SectionHeader) * section_table_len, | |
| 1096 | ); | |
| 1097 | const ni = try coff.mf.addLastChildNode(gpa, .root, .{ | |
| 1098 | .alignment = coff.mf.flags.block_size, | |
| 1099 | .moved = true, | |
| 1100 | .bubbles_moved = false, | |
| 1101 | }); | |
| 1102 | const si = coff.addSymbolAssumeCapacity(); | |
| 1103 | coff.section_table.appendAssumeCapacity(si); | |
| 1104 | coff.nodes.appendAssumeCapacity(.{ .section = si }); | |
| 1105 | const section_table = coff.sectionTableSlice(); | |
| 1106 | const virtual_size = coff.optionalHeaderField(.section_alignment); | |
| 1107 | const rva: u32 = switch (section_index) { | |
| 1108 | 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]), | |
| 1109 | else => coff.section_table.items[section_index - 1].get(coff).rva + | |
| 1110 | coff.targetLoad(&section_table[section_index - 1].virtual_size), | |
| 1111 | }; | |
| 1112 | { | |
| 1113 | const sym = si.get(coff); | |
| 1114 | sym.ni = ni; | |
| 1115 | sym.rva = rva; | |
| 1116 | sym.section_number = @enumFromInt(section_table_len); | |
| 1117 | sym.data_directory = maybe_data_directory; | |
| 1118 | } | |
| 1119 | const section = &section_table[section_index]; | |
| 1120 | section.* = .{ | |
| 1121 | .name = undefined, | |
| 1122 | .virtual_size = virtual_size, | |
| 1123 | .virtual_address = rva, | |
| 1124 | .size_of_raw_data = 0, | |
| 1125 | .pointer_to_raw_data = 0, | |
| 1126 | .pointer_to_relocations = 0, | |
| 1127 | .pointer_to_linenumbers = 0, | |
| 1128 | .number_of_relocations = 0, | |
| 1129 | .number_of_linenumbers = 0, | |
| 1130 | .flags = flags, | |
| 1131 | }; | |
| 1132 | @memcpy(section.name[0..name.len], name); | |
| 1133 | @memset(section.name[name.len..], 0); | |
| 1134 | if (coff.targetEndian() != native_endian) | |
| 1135 | std.mem.byteSwapAllFields(std.coff.SectionHeader, section); | |
| 1136 | if (maybe_data_directory) |data_directory| | |
| 1137 | coff.dataDirectoriesSlice()[@intFromEnum(data_directory)] = .{ | |
| 1138 | .virtual_address = section.virtual_address, | |
| 1139 | .size = section.virtual_size, | |
| 1140 | }; | |
| 1141 | switch (coff.optionalHeaderPtr()) { | |
| 1142 | inline else => |optional_header| coff.targetStore( | |
| 1143 | &optional_header.size_of_image, | |
| 1144 | @intCast(rva + virtual_size), | |
| 1145 | ), | |
| 1146 | } | |
| 1147 | return si; | |
| 1148 | } | |
| 1149 | ||
| 1150 | pub fn addReloc( | |
| 1151 | coff: *Coff, | |
| 1152 | loc_si: Symbol.Index, | |
| 1153 | offset: u64, | |
| 1154 | target_si: Symbol.Index, | |
| 1155 | addend: i64, | |
| 1156 | @"type": Reloc.Type, | |
| 1157 | ) !void { | |
| 1158 | const gpa = coff.base.comp.gpa; | |
| 1159 | const target = target_si.get(coff); | |
| 1160 | const ri: Reloc.Index = @enumFromInt(coff.relocs.items.len); | |
| 1161 | (try coff.relocs.addOne(gpa)).* = .{ | |
| 1162 | .type = @"type", | |
| 1163 | .prev = .none, | |
| 1164 | .next = target.target_relocs, | |
| 1165 | .loc = loc_si, | |
| 1166 | .target = target_si, | |
| 1167 | .unused = 0, | |
| 1168 | .offset = offset, | |
| 1169 | .addend = addend, | |
| 1170 | }; | |
| 1171 | switch (target.target_relocs) { | |
| 1172 | .none => {}, | |
| 1173 | else => |target_ri| target_ri.get(coff).prev = ri, | |
| 1174 | } | |
| 1175 | target.target_relocs = ri; | |
| 1176 | } | |
| 1177 | ||
| 1178 | pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) void { | |
| 1179 | _ = coff; | |
| 1180 | _ = prog_node; | |
| 1181 | } | |
| 1182 | ||
| 1183 | pub fn updateNav(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | |
| 1184 | coff.updateNavInner(pt, nav_index) catch |err| switch (err) { | |
| 1185 | error.OutOfMemory, | |
| 1186 | error.Overflow, | |
| 1187 | error.RelocationNotByteAligned, | |
| 1188 | => |e| return e, | |
| 1189 | else => |e| return coff.base.cgFail(nav_index, "linker failed to update variable: {t}", .{e}), | |
| 1190 | }; | |
| 1191 | } | |
| 1192 | fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | |
| 1193 | const zcu = pt.zcu; | |
| 1194 | const gpa = zcu.gpa; | |
| 1195 | const ip = &zcu.intern_pool; | |
| 1196 | ||
| 1197 | const nav = ip.getNav(nav_index); | |
| 1198 | const nav_val = nav.status.fully_resolved.val; | |
| 1199 | const nav_init, const is_threadlocal = switch (ip.indexToKey(nav_val)) { | |
| 1200 | else => .{ nav_val, false }, | |
| 1201 | .variable => |variable| .{ variable.init, variable.is_threadlocal }, | |
| 1202 | .@"extern" => return, | |
| 1203 | .func => .{ .none, false }, | |
| 1204 | }; | |
| 1205 | if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return; | |
| 1206 | ||
| 1207 | const nmi = try coff.navMapIndex(zcu, nav_index); | |
| 1208 | const si = nmi.symbol(coff); | |
| 1209 | const ni = ni: { | |
| 1210 | const sym = si.get(coff); | |
| 1211 | switch (sym.ni) { | |
| 1212 | .none => { | |
| 1213 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | |
| 1214 | _ = is_threadlocal; | |
| 1215 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.data.node(coff), .{ | |
| 1216 | .alignment = pt.navAlignment(nav_index).toStdMem(), | |
| 1217 | .moved = true, | |
| 1218 | }); | |
| 1219 | coff.nodes.appendAssumeCapacity(.{ .nav = nmi }); | |
| 1220 | sym.ni = ni; | |
| 1221 | sym.section_number = Symbol.Index.data.get(coff).section_number; | |
| 1222 | }, | |
| 1223 | else => si.deleteLocationRelocs(coff), | |
| 1224 | } | |
| 1225 | assert(sym.loc_relocs == .none); | |
| 1226 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | |
| 1227 | break :ni sym.ni; | |
| 1228 | }; | |
| 1229 | ||
| 1230 | var nw: MappedFile.Node.Writer = undefined; | |
| 1231 | ni.writer(&coff.mf, gpa, &nw); | |
| 1232 | defer nw.deinit(); | |
| 1233 | codegen.generateSymbol( | |
| 1234 | &coff.base, | |
| 1235 | pt, | |
| 1236 | zcu.navSrcLoc(nav_index), | |
| 1237 | .fromInterned(nav_init), | |
| 1238 | &nw.interface, | |
| 1239 | .{ .atom_index = @intFromEnum(si) }, | |
| 1240 | ) catch |err| switch (err) { | |
| 1241 | error.WriteFailed => return error.OutOfMemory, | |
| 1242 | else => |e| return e, | |
| 1243 | }; | |
| 1244 | si.get(coff).size = @intCast(nw.interface.end); | |
| 1245 | si.applyLocationRelocs(coff); | |
| 1246 | } | |
| 1247 | ||
| 1248 | pub fn lowerUav( | |
| 1249 | coff: *Coff, | |
| 1250 | pt: Zcu.PerThread, | |
| 1251 | uav_val: InternPool.Index, | |
| 1252 | uav_align: InternPool.Alignment, | |
| 1253 | src_loc: Zcu.LazySrcLoc, | |
| 1254 | ) !codegen.SymbolResult { | |
| 1255 | const zcu = pt.zcu; | |
| 1256 | const gpa = zcu.gpa; | |
| 1257 | ||
| 1258 | try coff.pending_uavs.ensureUnusedCapacity(gpa, 1); | |
| 1259 | const umi = try coff.uavMapIndex(uav_val); | |
| 1260 | const si = umi.symbol(coff); | |
| 1261 | if (switch (si.get(coff).ni) { | |
| 1262 | .none => true, | |
| 1263 | else => |ni| uav_align.toStdMem().order(ni.alignment(&coff.mf)).compare(.gt), | |
| 1264 | }) { | |
| 1265 | const gop = coff.pending_uavs.getOrPutAssumeCapacity(umi); | |
| 1266 | if (gop.found_existing) { | |
| 1267 | gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align); | |
| 1268 | } else { | |
| 1269 | gop.value_ptr.* = .{ | |
| 1270 | .alignment = uav_align, | |
| 1271 | .src_loc = src_loc, | |
| 1272 | }; | |
| 1273 | coff.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1); | |
| 1274 | } | |
| 1275 | } | |
| 1276 | return .{ .sym_index = @intFromEnum(si) }; | |
| 1277 | } | |
| 1278 | ||
| 1279 | pub fn updateFunc( | |
| 1280 | coff: *Coff, | |
| 1281 | pt: Zcu.PerThread, | |
| 1282 | func_index: InternPool.Index, | |
| 1283 | mir: *const codegen.AnyMir, | |
| 1284 | ) !void { | |
| 1285 | coff.updateFuncInner(pt, func_index, mir) catch |err| switch (err) { | |
| 1286 | error.OutOfMemory, | |
| 1287 | error.Overflow, | |
| 1288 | error.RelocationNotByteAligned, | |
| 1289 | error.CodegenFail, | |
| 1290 | => |e| return e, | |
| 1291 | else => |e| return coff.base.cgFail( | |
| 1292 | pt.zcu.funcInfo(func_index).owner_nav, | |
| 1293 | "linker failed to update function: {s}", | |
| 1294 | .{@errorName(e)}, | |
| 1295 | ), | |
| 1296 | }; | |
| 1297 | } | |
| 1298 | fn updateFuncInner( | |
| 1299 | coff: *Coff, | |
| 1300 | pt: Zcu.PerThread, | |
| 1301 | func_index: InternPool.Index, | |
| 1302 | mir: *const codegen.AnyMir, | |
| 1303 | ) !void { | |
| 1304 | const zcu = pt.zcu; | |
| 1305 | const gpa = zcu.gpa; | |
| 1306 | const ip = &zcu.intern_pool; | |
| 1307 | const func = zcu.funcInfo(func_index); | |
| 1308 | const nav = ip.getNav(func.owner_nav); | |
| 1309 | ||
| 1310 | const nmi = try coff.navMapIndex(zcu, func.owner_nav); | |
| 1311 | const si = nmi.symbol(coff); | |
| 1312 | log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si }); | |
| 1313 | const ni = ni: { | |
| 1314 | const sym = si.get(coff); | |
| 1315 | switch (sym.ni) { | |
| 1316 | .none => { | |
| 1317 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | |
| 1318 | const mod = zcu.navFileScope(func.owner_nav).mod.?; | |
| 1319 | const target = &mod.resolved_target.result; | |
| 1320 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ | |
| 1321 | .alignment = switch (nav.status.fully_resolved.alignment) { | |
| 1322 | .none => switch (mod.optimize_mode) { | |
| 1323 | .Debug, | |
| 1324 | .ReleaseSafe, | |
| 1325 | .ReleaseFast, | |
| 1326 | => target_util.defaultFunctionAlignment(target), | |
| 1327 | .ReleaseSmall => target_util.minFunctionAlignment(target), | |
| 1328 | }, | |
| 1329 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), | |
| 1330 | }.toStdMem(), | |
| 1331 | .moved = true, | |
| 1332 | }); | |
| 1333 | coff.nodes.appendAssumeCapacity(.{ .nav = nmi }); | |
| 1334 | sym.ni = ni; | |
| 1335 | sym.section_number = Symbol.Index.text.get(coff).section_number; | |
| 1336 | }, | |
| 1337 | else => si.deleteLocationRelocs(coff), | |
| 1338 | } | |
| 1339 | assert(sym.loc_relocs == .none); | |
| 1340 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | |
| 1341 | break :ni sym.ni; | |
| 1342 | }; | |
| 1343 | ||
| 1344 | var nw: MappedFile.Node.Writer = undefined; | |
| 1345 | ni.writer(&coff.mf, gpa, &nw); | |
| 1346 | defer nw.deinit(); | |
| 1347 | codegen.emitFunction( | |
| 1348 | &coff.base, | |
| 1349 | pt, | |
| 1350 | zcu.navSrcLoc(func.owner_nav), | |
| 1351 | func_index, | |
| 1352 | @intFromEnum(si), | |
| 1353 | mir, | |
| 1354 | &nw.interface, | |
| 1355 | .none, | |
| 1356 | ) catch |err| switch (err) { | |
| 1357 | error.WriteFailed => return nw.err.?, | |
| 1358 | else => |e| return e, | |
| 1359 | }; | |
| 1360 | si.get(coff).size = @intCast(nw.interface.end); | |
| 1361 | si.applyLocationRelocs(coff); | |
| 1362 | } | |
| 1363 | ||
| 1364 | pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void { | |
| 1365 | coff.flushLazy(pt, .{ | |
| 1366 | .kind = .const_data, | |
| 1367 | .index = @intCast(coff.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return), | |
| 1368 | }) catch |err| switch (err) { | |
| 1369 | error.OutOfMemory => return error.OutOfMemory, | |
| 1370 | error.CodegenFail => return error.LinkFailure, | |
| 1371 | else => |e| return coff.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}), | |
| 1372 | }; | |
| 1373 | } | |
| 1374 | ||
| 1375 | pub fn flush( | |
| 1376 | coff: *Coff, | |
| 1377 | arena: std.mem.Allocator, | |
| 1378 | tid: Zcu.PerThread.Id, | |
| 1379 | prog_node: std.Progress.Node, | |
| 1380 | ) !void { | |
| 1381 | _ = arena; | |
| 1382 | _ = prog_node; | |
| 1383 | while (try coff.idle(tid)) {} | |
| 1384 | ||
| 1385 | // hack for stage2_x86_64 + coff | |
| 1386 | const comp = coff.base.comp; | |
| 1387 | if (comp.compiler_rt_dyn_lib) |crt_file| { | |
| 1388 | const gpa = comp.gpa; | |
| 1389 | const compiler_rt_sub_path = try std.fs.path.join(gpa, &.{ | |
| 1390 | std.fs.path.dirname(coff.base.emit.sub_path) orelse "", | |
| 1391 | std.fs.path.basename(crt_file.full_object_path.sub_path), | |
| 1392 | }); | |
| 1393 | defer gpa.free(compiler_rt_sub_path); | |
| 1394 | crt_file.full_object_path.root_dir.handle.copyFile( | |
| 1395 | crt_file.full_object_path.sub_path, | |
| 1396 | coff.base.emit.root_dir.handle, | |
| 1397 | compiler_rt_sub_path, | |
| 1398 | .{}, | |
| 1399 | ) catch |err| switch (err) { | |
| 1400 | else => |e| return comp.link_diags.fail("Copy '{s}' failed: {s}", .{ | |
| 1401 | compiler_rt_sub_path, | |
| 1402 | @errorName(e), | |
| 1403 | }), | |
| 1404 | }; | |
| 1405 | } | |
| 1406 | } | |
| 1407 | ||
| 1408 | pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { | |
| 1409 | const comp = coff.base.comp; | |
| 1410 | task: { | |
| 1411 | while (coff.pending_uavs.pop()) |pending_uav| { | |
| 1412 | const sub_prog_node = coff.idleProgNode( | |
| 1413 | tid, | |
| 1414 | comp.link_const_prog_node, | |
| 1415 | .{ .uav = pending_uav.key }, | |
| 1416 | ); | |
| 1417 | defer sub_prog_node.end(); | |
| 1418 | coff.flushUav( | |
| 1419 | .{ .zcu = coff.base.comp.zcu.?, .tid = tid }, | |
| 1420 | pending_uav.key, | |
| 1421 | pending_uav.value.alignment, | |
| 1422 | pending_uav.value.src_loc, | |
| 1423 | ) catch |err| switch (err) { | |
| 1424 | error.OutOfMemory => return error.OutOfMemory, | |
| 1425 | else => |e| return coff.base.comp.link_diags.fail( | |
| 1426 | "linker failed to lower constant: {t}", | |
| 1427 | .{e}, | |
| 1428 | ), | |
| 1429 | }; | |
| 1430 | break :task; | |
| 1431 | } | |
| 1432 | if (coff.global_pending_index < coff.globals.count()) { | |
| 1433 | const pt: Zcu.PerThread = .{ .zcu = coff.base.comp.zcu.?, .tid = tid }; | |
| 1434 | const gmi: Node.GlobalMapIndex = @enumFromInt(coff.global_pending_index); | |
| 1435 | coff.global_pending_index += 1; | |
| 1436 | const sub_prog_node = comp.link_synth_prog_node.start( | |
| 1437 | gmi.globalName(coff).name.toSlice(coff), | |
| 1438 | 0, | |
| 1439 | ); | |
| 1440 | defer sub_prog_node.end(); | |
| 1441 | coff.flushGlobal(pt, gmi) catch |err| switch (err) { | |
| 1442 | error.OutOfMemory => return error.OutOfMemory, | |
| 1443 | else => |e| return coff.base.comp.link_diags.fail( | |
| 1444 | "linker failed to lower constant: {t}", | |
| 1445 | .{e}, | |
| 1446 | ), | |
| 1447 | }; | |
| 1448 | break :task; | |
| 1449 | } | |
| 1450 | var lazy_it = coff.lazy.iterator(); | |
| 1451 | while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { | |
| 1452 | const pt: Zcu.PerThread = .{ .zcu = coff.base.comp.zcu.?, .tid = tid }; | |
| 1453 | const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; | |
| 1454 | lazy.value.pending_index += 1; | |
| 1455 | const kind = switch (lmr.kind) { | |
| 1456 | .code => "code", | |
| 1457 | .const_data => "data", | |
| 1458 | }; | |
| 1459 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | |
| 1460 | const sub_prog_node = comp.link_synth_prog_node.start( | |
| 1461 | std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ | |
| 1462 | kind, | |
| 1463 | Type.fromInterned(lmr.lazySymbol(coff).ty).fmt(pt), | |
| 1464 | }) catch &name, | |
| 1465 | 0, | |
| 1466 | ); | |
| 1467 | defer sub_prog_node.end(); | |
| 1468 | coff.flushLazy(pt, lmr) catch |err| switch (err) { | |
| 1469 | error.OutOfMemory => return error.OutOfMemory, | |
| 1470 | else => |e| return coff.base.comp.link_diags.fail( | |
| 1471 | "linker failed to lower lazy {s}: {t}", | |
| 1472 | .{ kind, e }, | |
| 1473 | ), | |
| 1474 | }; | |
| 1475 | break :task; | |
| 1476 | }; | |
| 1477 | while (coff.mf.updates.pop()) |ni| { | |
| 1478 | const clean_moved = ni.cleanMoved(&coff.mf); | |
| 1479 | const clean_resized = ni.cleanResized(&coff.mf); | |
| 1480 | if (clean_moved or clean_resized) { | |
| 1481 | const sub_prog_node = coff.idleProgNode(tid, coff.mf.update_prog_node, coff.getNode(ni)); | |
| 1482 | defer sub_prog_node.end(); | |
| 1483 | if (clean_moved) try coff.flushMoved(ni); | |
| 1484 | if (clean_resized) try coff.flushResized(ni); | |
| 1485 | break :task; | |
| 1486 | } else coff.mf.update_prog_node.completeOne(); | |
| 1487 | } | |
| 1488 | } | |
| 1489 | if (coff.pending_uavs.count() > 0) return true; | |
| 1490 | for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; | |
| 1491 | if (coff.mf.updates.items.len > 0) return true; | |
| 1492 | return false; | |
| 1493 | } | |
| 1494 | ||
| 1495 | fn idleProgNode( | |
| 1496 | coff: *Coff, | |
| 1497 | tid: Zcu.PerThread.Id, | |
| 1498 | prog_node: std.Progress.Node, | |
| 1499 | node: Node, | |
| 1500 | ) std.Progress.Node { | |
| 1501 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | |
| 1502 | return prog_node.start(name: switch (node) { | |
| 1503 | else => |tag| @tagName(tag), | |
| 1504 | .section => |si| std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0), | |
| 1505 | .nav => |nmi| { | |
| 1506 | const ip = &coff.base.comp.zcu.?.intern_pool; | |
| 1507 | break :name ip.getNav(nmi.navIndex(coff)).fqn.toSlice(ip); | |
| 1508 | }, | |
| 1509 | .uav => |umi| std.fmt.bufPrint(&name, "{f}", .{ | |
| 1510 | Value.fromInterned(umi.uavValue(coff)).fmtValue(.{ | |
| 1511 | .zcu = coff.base.comp.zcu.?, | |
| 1512 | .tid = tid, | |
| 1513 | }), | |
| 1514 | }) catch &name, | |
| 1515 | }, 0); | |
| 1516 | } | |
| 1517 | ||
| 1518 | fn flushUav( | |
| 1519 | coff: *Coff, | |
| 1520 | pt: Zcu.PerThread, | |
| 1521 | umi: Node.UavMapIndex, | |
| 1522 | uav_align: InternPool.Alignment, | |
| 1523 | src_loc: Zcu.LazySrcLoc, | |
| 1524 | ) !void { | |
| 1525 | const zcu = pt.zcu; | |
| 1526 | const gpa = zcu.gpa; | |
| 1527 | ||
| 1528 | const uav_val = umi.uavValue(coff); | |
| 1529 | const si = umi.symbol(coff); | |
| 1530 | const ni = ni: { | |
| 1531 | const sym = si.get(coff); | |
| 1532 | switch (sym.ni) { | |
| 1533 | .none => { | |
| 1534 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | |
| 1535 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.data.node(coff), .{ | |
| 1536 | .alignment = uav_align.toStdMem(), | |
| 1537 | .moved = true, | |
| 1538 | }); | |
| 1539 | coff.nodes.appendAssumeCapacity(.{ .uav = umi }); | |
| 1540 | sym.ni = ni; | |
| 1541 | sym.section_number = Symbol.Index.data.get(coff).section_number; | |
| 1542 | }, | |
| 1543 | else => { | |
| 1544 | if (sym.ni.alignment(&coff.mf).order(uav_align.toStdMem()).compare(.gte)) return; | |
| 1545 | si.deleteLocationRelocs(coff); | |
| 1546 | }, | |
| 1547 | } | |
| 1548 | assert(sym.loc_relocs == .none); | |
| 1549 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | |
| 1550 | break :ni sym.ni; | |
| 1551 | }; | |
| 1552 | ||
| 1553 | var nw: MappedFile.Node.Writer = undefined; | |
| 1554 | ni.writer(&coff.mf, gpa, &nw); | |
| 1555 | defer nw.deinit(); | |
| 1556 | codegen.generateSymbol( | |
| 1557 | &coff.base, | |
| 1558 | pt, | |
| 1559 | src_loc, | |
| 1560 | .fromInterned(uav_val), | |
| 1561 | &nw.interface, | |
| 1562 | .{ .atom_index = @intFromEnum(si) }, | |
| 1563 | ) catch |err| switch (err) { | |
| 1564 | error.WriteFailed => return error.OutOfMemory, | |
| 1565 | else => |e| return e, | |
| 1566 | }; | |
| 1567 | si.get(coff).size = @intCast(nw.interface.end); | |
| 1568 | si.applyLocationRelocs(coff); | |
| 1569 | } | |
| 1570 | ||
| 1571 | fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { | |
| 1572 | const zcu = pt.zcu; | |
| 1573 | const comp = zcu.comp; | |
| 1574 | const gpa = zcu.gpa; | |
| 1575 | const gn = gmi.globalName(coff); | |
| 1576 | if (gn.lib_name.toSlice(coff)) |lib_name| { | |
| 1577 | const name = gn.name.toSlice(coff); | |
| 1578 | try coff.nodes.ensureUnusedCapacity(gpa, 4); | |
| 1579 | try coff.symbol_table.ensureUnusedCapacity(gpa, 1); | |
| 1580 | ||
| 1581 | const target_endian = coff.targetEndian(); | |
| 1582 | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); | |
| 1583 | const addr_size: u64, const addr_align: std.mem.Alignment = switch (magic) { | |
| 1584 | _ => unreachable, | |
| 1585 | .PE32 => .{ 4, .@"4" }, | |
| 1586 | .@"PE32+" => .{ 8, .@"8" }, | |
| 1587 | }; | |
| 1588 | ||
| 1589 | const gop = try coff.import_table.dlls.getOrPutAdapted( | |
| 1590 | gpa, | |
| 1591 | lib_name, | |
| 1592 | ImportTable.Adapter{ .coff = coff }, | |
| 1593 | ); | |
| 1594 | const import_hint_name_align: std.mem.Alignment = .@"2"; | |
| 1595 | if (!gop.found_existing) { | |
| 1596 | errdefer _ = coff.import_table.dlls.pop(); | |
| 1597 | try coff.import_table.directory_table_ni.resize( | |
| 1598 | &coff.mf, | |
| 1599 | gpa, | |
| 1600 | @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2), | |
| 1601 | ); | |
| 1602 | const import_hint_name_table_len = | |
| 1603 | import_hint_name_align.forward(lib_name.len + ".dll".len + 1); | |
| 1604 | const idata_section_ni = Symbol.Index.idata.node(coff); | |
| 1605 | const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ | |
| 1606 | .size = addr_size * 2, | |
| 1607 | .alignment = addr_align, | |
| 1608 | .moved = true, | |
| 1609 | }); | |
| 1610 | const import_address_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ | |
| 1611 | .size = addr_size * 2, | |
| 1612 | .alignment = addr_align, | |
| 1613 | .moved = true, | |
| 1614 | }); | |
| 1615 | const import_address_table_si = coff.addSymbolAssumeCapacity(); | |
| 1616 | { | |
| 1617 | const import_address_table_sym = import_address_table_si.get(coff); | |
| 1618 | import_address_table_sym.ni = import_address_table_ni; | |
| 1619 | assert(import_address_table_sym.loc_relocs == .none); | |
| 1620 | import_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | |
| 1621 | import_address_table_sym.section_number = Symbol.Index.idata.get(coff).section_number; | |
| 1622 | } | |
| 1623 | const import_hint_name_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ | |
| 1624 | .size = import_hint_name_table_len, | |
| 1625 | .alignment = import_hint_name_align, | |
| 1626 | .moved = true, | |
| 1627 | }); | |
| 1628 | gop.value_ptr.* = .{ | |
| 1629 | .import_lookup_table_ni = import_lookup_table_ni, | |
| 1630 | .import_address_table_si = import_address_table_si, | |
| 1631 | .import_hint_name_table_ni = import_hint_name_table_ni, | |
| 1632 | .len = 0, | |
| 1633 | .hint_name_len = @intCast(import_hint_name_table_len), | |
| 1634 | }; | |
| 1635 | const import_hint_name_slice = import_hint_name_table_ni.slice(&coff.mf); | |
| 1636 | @memcpy(import_hint_name_slice[0..lib_name.len], lib_name); | |
| 1637 | @memcpy(import_hint_name_slice[lib_name.len..][0..".dll".len], ".dll"); | |
| 1638 | @memset(import_hint_name_slice[lib_name.len + ".dll".len ..], 0); | |
| 1639 | coff.nodes.appendAssumeCapacity(.{ .import_lookup_table = @intCast(gop.index) }); | |
| 1640 | coff.nodes.appendAssumeCapacity(.{ .import_address_table = @intCast(gop.index) }); | |
| 1641 | coff.nodes.appendAssumeCapacity(.{ .import_hint_name_table = @intCast(gop.index) }); | |
| 1642 | ||
| 1643 | const import_directory_table: []std.coff.ImportDirectoryEntry = | |
| 1644 | @ptrCast(@alignCast(coff.import_table.directory_table_ni.slice(&coff.mf))); | |
| 1645 | import_directory_table[gop.index..][0..2].* = .{ .{ | |
| 1646 | .import_lookup_table_rva = coff.computeNodeRva(import_lookup_table_ni), | |
| 1647 | .time_date_stamp = 0, | |
| 1648 | .forwarder_chain = 0, | |
| 1649 | .name_rva = coff.computeNodeRva(import_hint_name_table_ni), | |
| 1650 | .import_address_table_rva = coff.computeNodeRva(import_address_table_ni), | |
| 1651 | }, .{ | |
| 1652 | .import_lookup_table_rva = 0, | |
| 1653 | .time_date_stamp = 0, | |
| 1654 | .forwarder_chain = 0, | |
| 1655 | .name_rva = 0, | |
| 1656 | .import_address_table_rva = 0, | |
| 1657 | } }; | |
| 1658 | } | |
| 1659 | const import_symbol_index = gop.value_ptr.len; | |
| 1660 | gop.value_ptr.len = import_symbol_index + 1; | |
| 1661 | const new_symbol_table_size = addr_size * (import_symbol_index + 2); | |
| 1662 | const import_hint_name_index = gop.value_ptr.hint_name_len; | |
| 1663 | gop.value_ptr.hint_name_len = @intCast( | |
| 1664 | import_hint_name_align.forward(import_hint_name_index + 2 + name.len + 1), | |
| 1665 | ); | |
| 1666 | try gop.value_ptr.import_lookup_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); | |
| 1667 | const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff); | |
| 1668 | try import_address_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); | |
| 1669 | try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len); | |
| 1670 | const import_lookup_slice = gop.value_ptr.import_lookup_table_ni.slice(&coff.mf); | |
| 1671 | const import_address_slice = import_address_table_ni.slice(&coff.mf); | |
| 1672 | const import_hint_name_slice = gop.value_ptr.import_hint_name_table_ni.slice(&coff.mf); | |
| 1673 | @memset(import_hint_name_slice[import_hint_name_index..][0..2], 0); | |
| 1674 | @memcpy(import_hint_name_slice[import_hint_name_index + 2 ..][0..name.len], name); | |
| 1675 | @memset(import_hint_name_slice[import_hint_name_index + 2 + name.len ..], 0); | |
| 1676 | const import_hint_name_rva = | |
| 1677 | coff.computeNodeRva(gop.value_ptr.import_hint_name_table_ni) + import_hint_name_index; | |
| 1678 | switch (magic) { | |
| 1679 | _ => unreachable, | |
| 1680 | inline .PE32, .@"PE32+" => |ct_magic| { | |
| 1681 | const Addr = switch (ct_magic) { | |
| 1682 | _ => comptime unreachable, | |
| 1683 | .PE32 => u32, | |
| 1684 | .@"PE32+" => u64, | |
| 1685 | }; | |
| 1686 | const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); | |
| 1687 | const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); | |
| 1688 | const import_hint_name_rvas: [2]Addr = .{ | |
| 1689 | std.mem.nativeTo(Addr, @intCast(import_hint_name_rva), target_endian), | |
| 1690 | std.mem.nativeTo(Addr, 0, target_endian), | |
| 1691 | }; | |
| 1692 | import_lookup_table[import_symbol_index..][0..2].* = import_hint_name_rvas; | |
| 1693 | import_address_table[import_symbol_index..][0..2].* = import_hint_name_rvas; | |
| 1694 | }, | |
| 1695 | } | |
| 1696 | const si = gmi.symbol(coff); | |
| 1697 | const sym = si.get(coff); | |
| 1698 | sym.section_number = Symbol.Index.text.get(coff).section_number; | |
| 1699 | assert(sym.loc_relocs == .none); | |
| 1700 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | |
| 1701 | switch (coff.targetLoad(&coff.headerPtr().machine)) { | |
| 1702 | else => |tag| @panic(@tagName(tag)), | |
| 1703 | .AMD64 => { | |
| 1704 | const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; | |
| 1705 | const target = &comp.root_mod.resolved_target.result; | |
| 1706 | const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ | |
| 1707 | .alignment = switch (comp.root_mod.optimize_mode) { | |
| 1708 | .Debug, | |
| 1709 | .ReleaseSafe, | |
| 1710 | .ReleaseFast, | |
| 1711 | => target_util.defaultFunctionAlignment(target), | |
| 1712 | .ReleaseSmall => target_util.minFunctionAlignment(target), | |
| 1713 | }.toStdMem(), | |
| 1714 | .size = init.len, | |
| 1715 | }); | |
| 1716 | @memcpy(ni.slice(&coff.mf)[0..init.len], &init); | |
| 1717 | sym.ni = ni; | |
| 1718 | sym.size = init.len; | |
| 1719 | try coff.addReloc( | |
| 1720 | si, | |
| 1721 | init.len - 4, | |
| 1722 | gop.value_ptr.import_address_table_si, | |
| 1723 | @intCast(addr_size * import_symbol_index), | |
| 1724 | .{ .AMD64 = .REL32 }, | |
| 1725 | ); | |
| 1726 | }, | |
| 1727 | } | |
| 1728 | coff.nodes.appendAssumeCapacity(.{ .global = gmi }); | |
| 1729 | sym.rva = coff.computeNodeRva(sym.ni); | |
| 1730 | si.applyLocationRelocs(coff); | |
| 1731 | } | |
| 1732 | } | |
| 1733 | ||
| 1734 | fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | |
| 1735 | const zcu = pt.zcu; | |
| 1736 | const gpa = zcu.gpa; | |
| 1737 | ||
| 1738 | const lazy = lmr.lazySymbol(coff); | |
| 1739 | const si = lmr.symbol(coff); | |
| 1740 | const ni = ni: { | |
| 1741 | const sym = si.get(coff); | |
| 1742 | switch (sym.ni) { | |
| 1743 | .none => { | |
| 1744 | try coff.nodes.ensureUnusedCapacity(gpa, 1); | |
| 1745 | const sec_si: Symbol.Index = switch (lazy.kind) { | |
| 1746 | .code => .text, | |
| 1747 | .const_data => .rdata, | |
| 1748 | }; | |
| 1749 | const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ .moved = true }); | |
| 1750 | coff.nodes.appendAssumeCapacity(switch (lazy.kind) { | |
| 1751 | .code => .{ .lazy_code = @enumFromInt(lmr.index) }, | |
| 1752 | .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) }, | |
| 1753 | }); | |
| 1754 | sym.ni = ni; | |
| 1755 | sym.section_number = sec_si.get(coff).section_number; | |
| 1756 | }, | |
| 1757 | else => si.deleteLocationRelocs(coff), | |
| 1758 | } | |
| 1759 | assert(sym.loc_relocs == .none); | |
| 1760 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | |
| 1761 | break :ni sym.ni; | |
| 1762 | }; | |
| 1763 | ||
| 1764 | var required_alignment: InternPool.Alignment = .none; | |
| 1765 | var nw: MappedFile.Node.Writer = undefined; | |
| 1766 | ni.writer(&coff.mf, gpa, &nw); | |
| 1767 | defer nw.deinit(); | |
| 1768 | try codegen.generateLazySymbol( | |
| 1769 | &coff.base, | |
| 1770 | pt, | |
| 1771 | Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded, | |
| 1772 | lazy, | |
| 1773 | &required_alignment, | |
| 1774 | &nw.interface, | |
| 1775 | .none, | |
| 1776 | .{ .atom_index = @intFromEnum(si) }, | |
| 1777 | ); | |
| 1778 | si.get(coff).size = @intCast(nw.interface.end); | |
| 1779 | si.applyLocationRelocs(coff); | |
| 1780 | } | |
| 1781 | ||
| 1782 | fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { | |
| 1783 | const node = coff.getNode(ni); | |
| 1784 | switch (node) { | |
| 1785 | else => |tag| @panic(@tagName(tag)), | |
| 1786 | .section => |si| return coff.targetStore( | |
| 1787 | &si.get(coff).section_number.header(coff).pointer_to_raw_data, | |
| 1788 | @intCast(ni.fileLocation(&coff.mf, false).offset), | |
| 1789 | ), | |
| 1790 | .import_directory_table => {}, | |
| 1791 | .import_lookup_table => |import_directory_table_index| { | |
| 1792 | const import_directory_table: []std.coff.ImportDirectoryEntry = | |
| 1793 | @ptrCast(@alignCast(coff.import_table.directory_table_ni.slice(&coff.mf))); | |
| 1794 | const import_directory_entry = &import_directory_table[import_directory_table_index]; | |
| 1795 | coff.targetStore(&import_directory_entry.import_lookup_table_rva, coff.computeNodeRva(ni)); | |
| 1796 | }, | |
| 1797 | .import_address_table => |import_directory_table_index| { | |
| 1798 | const import_directory_table: []std.coff.ImportDirectoryEntry = | |
| 1799 | @ptrCast(@alignCast(coff.import_table.directory_table_ni.slice(&coff.mf))); | |
| 1800 | const import_directory_entry = &import_directory_table[import_directory_table_index]; | |
| 1801 | coff.targetStore(&import_directory_entry.import_lookup_table_rva, coff.computeNodeRva(ni)); | |
| 1802 | const import_address_table_si = | |
| 1803 | coff.import_table.dlls.values()[import_directory_table_index].import_address_table_si; | |
| 1804 | import_address_table_si.flushMoved(coff); | |
| 1805 | coff.targetStore( | |
| 1806 | &import_directory_entry.import_address_table_rva, | |
| 1807 | import_address_table_si.get(coff).rva, | |
| 1808 | ); | |
| 1809 | }, | |
| 1810 | .import_hint_name_table => |import_directory_table_index| { | |
| 1811 | const target_endian = coff.targetEndian(); | |
| 1812 | const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); | |
| 1813 | const import_directory_table: []std.coff.ImportDirectoryEntry = | |
| 1814 | @ptrCast(@alignCast(coff.import_table.directory_table_ni.slice(&coff.mf))); | |
| 1815 | const import_directory_entry = &import_directory_table[import_directory_table_index]; | |
| 1816 | const import_hint_name_rva = coff.computeNodeRva(ni); | |
| 1817 | coff.targetStore(&import_directory_entry.name_rva, import_hint_name_rva); | |
| 1818 | const import_entry = &coff.import_table.dlls.values()[import_directory_table_index]; | |
| 1819 | const import_lookup_slice = import_entry.import_lookup_table_ni.slice(&coff.mf); | |
| 1820 | const import_address_slice = | |
| 1821 | import_entry.import_address_table_si.node(coff).slice(&coff.mf); | |
| 1822 | const import_hint_name_slice = ni.slice(&coff.mf); | |
| 1823 | const import_hint_name_align = ni.alignment(&coff.mf); | |
| 1824 | var import_hint_name_index: u32 = 0; | |
| 1825 | for (0..import_entry.len) |import_symbol_index| { | |
| 1826 | import_hint_name_index = @intCast(import_hint_name_align.forward( | |
| 1827 | std.mem.indexOfScalarPos( | |
| 1828 | u8, | |
| 1829 | import_hint_name_slice, | |
| 1830 | import_hint_name_index, | |
| 1831 | 0, | |
| 1832 | ).? + 1, | |
| 1833 | )); | |
| 1834 | switch (magic) { | |
| 1835 | _ => unreachable, | |
| 1836 | inline .PE32, .@"PE32+" => |ct_magic| { | |
| 1837 | const Addr = switch (ct_magic) { | |
| 1838 | _ => comptime unreachable, | |
| 1839 | .PE32 => u32, | |
| 1840 | .@"PE32+" => u64, | |
| 1841 | }; | |
| 1842 | const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); | |
| 1843 | const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); | |
| 1844 | const rva = std.mem.nativeTo( | |
| 1845 | Addr, | |
| 1846 | import_hint_name_rva + import_hint_name_index, | |
| 1847 | target_endian, | |
| 1848 | ); | |
| 1849 | import_lookup_table[import_symbol_index] = rva; | |
| 1850 | import_address_table[import_symbol_index] = rva; | |
| 1851 | }, | |
| 1852 | } | |
| 1853 | import_hint_name_index += 2; | |
| 1854 | } | |
| 1855 | }, | |
| 1856 | inline .global, | |
| 1857 | .nav, | |
| 1858 | .uav, | |
| 1859 | .lazy_code, | |
| 1860 | .lazy_const_data, | |
| 1861 | => |mi| mi.symbol(coff).flushMoved(coff), | |
| 1862 | } | |
| 1863 | try ni.childrenMoved(coff.base.comp.gpa, &coff.mf); | |
| 1864 | } | |
| 1865 | ||
| 1866 | fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { | |
| 1867 | _, const size = ni.location(&coff.mf).resolve(&coff.mf); | |
| 1868 | const node = coff.getNode(ni); | |
| 1869 | switch (node) { | |
| 1870 | else => |tag| @panic(@tagName(tag)), | |
| 1871 | .file => {}, | |
| 1872 | .header => { | |
| 1873 | switch (coff.optionalHeaderPtr()) { | |
| 1874 | inline else => |optional_header| coff.targetStore( | |
| 1875 | &optional_header.size_of_headers, | |
| 1876 | @intCast(size), | |
| 1877 | ), | |
| 1878 | } | |
| 1879 | if (size > coff.section_table.items[0].get(coff).rva) try coff.virtualSlide( | |
| 1880 | 0, | |
| 1881 | std.mem.alignForward( | |
| 1882 | u32, | |
| 1883 | @intCast(size * 4), | |
| 1884 | coff.optionalHeaderField(.section_alignment), | |
| 1885 | ), | |
| 1886 | ); | |
| 1887 | }, | |
| 1888 | .section_table => {}, | |
| 1889 | .section => |si| { | |
| 1890 | const sym = si.get(coff); | |
| 1891 | const section_table = coff.sectionTableSlice(); | |
| 1892 | const section_index = sym.section_number.toIndex(); | |
| 1893 | const section = &section_table[section_index]; | |
| 1894 | coff.targetStore(&section.size_of_raw_data, @intCast(size)); | |
| 1895 | if (size > coff.targetLoad(&section.virtual_size)) { | |
| 1896 | const virtual_size = std.mem.alignForward( | |
| 1897 | u32, | |
| 1898 | @intCast(size * 4), | |
| 1899 | coff.optionalHeaderField(.section_alignment), | |
| 1900 | ); | |
| 1901 | coff.targetStore(&section.virtual_size, virtual_size); | |
| 1902 | if (sym.data_directory) |data_directory| | |
| 1903 | coff.dataDirectoriesSlice()[@intFromEnum(data_directory)].size = | |
| 1904 | section.virtual_size; | |
| 1905 | try coff.virtualSlide(section_index + 1, sym.rva + virtual_size); | |
| 1906 | } | |
| 1907 | }, | |
| 1908 | .import_directory_table, | |
| 1909 | .import_lookup_table, | |
| 1910 | .import_address_table, | |
| 1911 | .import_hint_name_table, | |
| 1912 | .global, | |
| 1913 | .nav, | |
| 1914 | .uav, | |
| 1915 | .lazy_code, | |
| 1916 | .lazy_const_data, | |
| 1917 | => {}, | |
| 1918 | } | |
| 1919 | } | |
| 1920 | ||
| 1921 | fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void { | |
| 1922 | const section_table = coff.sectionTableSlice(); | |
| 1923 | var rva = start_rva; | |
| 1924 | for ( | |
| 1925 | coff.section_table.items[start_section_index..], | |
| 1926 | section_table[start_section_index..], | |
| 1927 | ) |section_si, *section| { | |
| 1928 | const section_sym = section_si.get(coff); | |
| 1929 | section_sym.rva = rva; | |
| 1930 | coff.targetStore(&section.virtual_address, rva); | |
| 1931 | if (section_sym.data_directory) |data_directory| | |
| 1932 | coff.dataDirectoriesSlice()[@intFromEnum(data_directory)].virtual_address = | |
| 1933 | section.virtual_address; | |
| 1934 | try section_sym.ni.childrenMoved(coff.base.comp.gpa, &coff.mf); | |
| 1935 | rva += coff.targetLoad(&section.virtual_size); | |
| 1936 | } | |
| 1937 | switch (coff.optionalHeaderPtr()) { | |
| 1938 | inline else => |optional_header| coff.targetStore( | |
| 1939 | &optional_header.size_of_image, | |
| 1940 | @intCast(rva), | |
| 1941 | ), | |
| 1942 | } | |
| 1943 | } | |
| 1944 | ||
| 1945 | pub fn updateExports( | |
| 1946 | coff: *Coff, | |
| 1947 | pt: Zcu.PerThread, | |
| 1948 | exported: Zcu.Exported, | |
| 1949 | export_indices: []const Zcu.Export.Index, | |
| 1950 | ) !void { | |
| 1951 | return coff.updateExportsInner(pt, exported, export_indices) catch |err| switch (err) { | |
| 1952 | error.OutOfMemory => error.OutOfMemory, | |
| 1953 | error.LinkFailure => error.AnalysisFail, | |
| 1954 | }; | |
| 1955 | } | |
| 1956 | fn updateExportsInner( | |
| 1957 | coff: *Coff, | |
| 1958 | pt: Zcu.PerThread, | |
| 1959 | exported: Zcu.Exported, | |
| 1960 | export_indices: []const Zcu.Export.Index, | |
| 1961 | ) !void { | |
| 1962 | const zcu = pt.zcu; | |
| 1963 | const gpa = zcu.gpa; | |
| 1964 | const ip = &zcu.intern_pool; | |
| 1965 | ||
| 1966 | switch (exported) { | |
| 1967 | .nav => |nav| log.debug("updateExports({f})", .{ip.getNav(nav).fqn.fmt(ip)}), | |
| 1968 | .uav => |uav| log.debug("updateExports(@as({f}, {f}))", .{ | |
| 1969 | Type.fromInterned(ip.typeOf(uav)).fmt(pt), | |
| 1970 | Value.fromInterned(uav).fmtValue(pt), | |
| 1971 | }), | |
| 1972 | } | |
| 1973 | try coff.symbol_table.ensureUnusedCapacity(gpa, export_indices.len); | |
| 1974 | const exported_si: Symbol.Index = switch (exported) { | |
| 1975 | .nav => |nav| try coff.navSymbol(zcu, nav), | |
| 1976 | .uav => |uav| @enumFromInt(switch (try coff.lowerUav( | |
| 1977 | pt, | |
| 1978 | uav, | |
| 1979 | Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu), | |
| 1980 | export_indices[0].ptr(zcu).src, | |
| 1981 | )) { | |
| 1982 | .sym_index => |si| si, | |
| 1983 | .fail => |em| { | |
| 1984 | defer em.destroy(gpa); | |
| 1985 | return coff.base.comp.link_diags.fail("{s}", .{em.msg}); | |
| 1986 | }, | |
| 1987 | }), | |
| 1988 | }; | |
| 1989 | while (try coff.idle(pt.tid)) {} | |
| 1990 | const exported_ni = exported_si.node(coff); | |
| 1991 | const exported_sym = exported_si.get(coff); | |
| 1992 | for (export_indices) |export_index| { | |
| 1993 | const @"export" = export_index.ptr(zcu); | |
| 1994 | const export_si = try coff.globalSymbol(@"export".opts.name.toSlice(ip), null); | |
| 1995 | const export_sym = export_si.get(coff); | |
| 1996 | export_sym.ni = exported_ni; | |
| 1997 | export_sym.rva = exported_sym.rva; | |
| 1998 | export_sym.size = exported_sym.size; | |
| 1999 | export_sym.section_number = exported_sym.section_number; | |
| 2000 | export_si.applyTargetRelocs(coff); | |
| 2001 | if (@"export".opts.name.eqlSlice("wWinMainCRTStartup", ip)) { | |
| 2002 | coff.entry_hack = exported_si; | |
| 2003 | coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva; | |
| 2004 | } | |
| 2005 | } | |
| 2006 | } | |
| 2007 | ||
| 2008 | pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void { | |
| 2009 | _ = coff; | |
| 2010 | _ = exported; | |
| 2011 | _ = name; | |
| 2012 | } | |
| 2013 | ||
| 2014 | pub fn dump(coff: *Coff, tid: Zcu.PerThread.Id) void { | |
| 2015 | const w = std.debug.lockStderrWriter(&.{}); | |
| 2016 | defer std.debug.unlockStderrWriter(); | |
| 2017 | coff.printNode(tid, w, .root, 0) catch {}; | |
| 2018 | } | |
| 2019 | ||
| 2020 | pub fn printNode( | |
| 2021 | coff: *Coff, | |
| 2022 | tid: Zcu.PerThread.Id, | |
| 2023 | w: *std.Io.Writer, | |
| 2024 | ni: MappedFile.Node.Index, | |
| 2025 | indent: usize, | |
| 2026 | ) !void { | |
| 2027 | const node = coff.getNode(ni); | |
| 2028 | try w.splatByteAll(' ', indent); | |
| 2029 | try w.writeAll(@tagName(node)); | |
| 2030 | switch (node) { | |
| 2031 | else => {}, | |
| 2032 | .section => |si| try w.print("({s})", .{ | |
| 2033 | std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0), | |
| 2034 | }), | |
| 2035 | .import_lookup_table, | |
| 2036 | .import_address_table, | |
| 2037 | .import_hint_name_table, | |
| 2038 | => |import_directory_table_index| try w.print("({s})", .{ | |
| 2039 | std.mem.sliceTo(coff.import_table.dlls.values()[import_directory_table_index] | |
| 2040 | .import_hint_name_table_ni.sliceConst(&coff.mf), 0), | |
| 2041 | }), | |
| 2042 | .global => |gmi| { | |
| 2043 | const gn = gmi.globalName(coff); | |
| 2044 | try w.writeByte('('); | |
| 2045 | if (gn.lib_name.toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); | |
| 2046 | try w.print("{s})", .{gn.name.toSlice(coff)}); | |
| 2047 | }, | |
| 2048 | .nav => |nmi| { | |
| 2049 | const zcu = coff.base.comp.zcu.?; | |
| 2050 | const ip = &zcu.intern_pool; | |
| 2051 | const nav = ip.getNav(nmi.navIndex(coff)); | |
| 2052 | try w.print("({f}, {f})", .{ | |
| 2053 | Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }), | |
| 2054 | nav.fqn.fmt(ip), | |
| 2055 | }); | |
| 2056 | }, | |
| 2057 | .uav => |umi| { | |
| 2058 | const zcu = coff.base.comp.zcu.?; | |
| 2059 | const val: Value = .fromInterned(umi.uavValue(coff)); | |
| 2060 | try w.print("({f}, {f})", .{ | |
| 2061 | val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }), | |
| 2062 | val.fmtValue(.{ .zcu = zcu, .tid = tid }), | |
| 2063 | }); | |
| 2064 | }, | |
| 2065 | inline .lazy_code, .lazy_const_data => |lmi| try w.print("({f})", .{ | |
| 2066 | Type.fromInterned(lmi.lazySymbol(coff).ty).fmt(.{ | |
| 2067 | .zcu = coff.base.comp.zcu.?, | |
| 2068 | .tid = tid, | |
| 2069 | }), | |
| 2070 | }), | |
| 2071 | } | |
| 2072 | { | |
| 2073 | const mf_node = &coff.mf.nodes.items[@intFromEnum(ni)]; | |
| 2074 | const off, const size = mf_node.location().resolve(&coff.mf); | |
| 2075 | try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{ | |
| 2076 | @intFromEnum(ni), | |
| 2077 | off, | |
| 2078 | size, | |
| 2079 | mf_node.flags.alignment.toByteUnits(), | |
| 2080 | if (mf_node.flags.fixed) " fixed" else "", | |
| 2081 | if (mf_node.flags.moved) " moved" else "", | |
| 2082 | if (mf_node.flags.resized) " resized" else "", | |
| 2083 | if (mf_node.flags.has_content) " has_content" else "", | |
| 2084 | }); | |
| 2085 | } | |
| 2086 | var leaf = true; | |
| 2087 | var child_it = ni.children(&coff.mf); | |
| 2088 | while (child_it.next()) |child_ni| { | |
| 2089 | leaf = false; | |
| 2090 | try coff.printNode(tid, w, child_ni, indent + 1); | |
| 2091 | } | |
| 2092 | if (leaf) { | |
| 2093 | const file_loc = ni.fileLocation(&coff.mf, false); | |
| 2094 | if (file_loc.size == 0) return; | |
| 2095 | var address = file_loc.offset; | |
| 2096 | const line_len = 0x10; | |
| 2097 | var line_it = std.mem.window( | |
| 2098 | u8, | |
| 2099 | coff.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], | |
| 2100 | line_len, | |
| 2101 | line_len, | |
| 2102 | ); | |
| 2103 | while (line_it.next()) |line_bytes| : (address += line_len) { | |
| 2104 | try w.splatByteAll(' ', indent + 1); | |
| 2105 | try w.print("{x:0>8} ", .{address}); | |
| 2106 | for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte}); | |
| 2107 | try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1); | |
| 2108 | for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.'); | |
| 2109 | try w.writeByte('\n'); | |
| 2110 | } | |
| 2111 | } | |
| 2112 | } | |
| 2113 | ||
| 2114 | const assert = std.debug.assert; | |
| 2115 | const builtin = @import("builtin"); | |
| 2116 | const codegen = @import("../codegen.zig"); | |
| 2117 | const Compilation = @import("../Compilation.zig"); | |
| 2118 | const Coff = @This(); | |
| 2119 | const InternPool = @import("../InternPool.zig"); | |
| 2120 | const link = @import("../link.zig"); | |
| 2121 | const log = std.log.scoped(.link); | |
| 2122 | const MappedFile = @import("MappedFile.zig"); | |
| 2123 | const native_endian = builtin.cpu.arch.endian(); | |
| 2124 | const std = @import("std"); | |
| 2125 | const target_util = @import("../target.zig"); | |
| 2126 | const Type = @import("../Type.zig"); | |
| 2127 | const Value = @import("../Value.zig"); | |
| 2128 | const Zcu = @import("../Zcu.zig"); |
src/link/Elf2.zig+325-303| ... | ... | @@ -11,7 +11,7 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { |
| 11 | 11 | map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), |
| 12 | 12 | pending_index: u32, |
| 13 | 13 | }), |
| 14 | pending_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct { | |
| 14 | pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { | |
| 15 | 15 | alignment: InternPool.Alignment, |
| 16 | 16 | src_loc: Zcu.LazySrcLoc, |
| 17 | 17 | }), |
| ... | ... | @@ -25,10 +25,65 @@ pub const Node = union(enum) { |
| 25 | 25 | shdr, |
| 26 | 26 | segment: u32, |
| 27 | 27 | section: Symbol.Index, |
| 28 | nav: InternPool.Nav.Index, | |
| 29 | uav: InternPool.Index, | |
| 30 | lazy_code: InternPool.Index, | |
| 31 | lazy_const_data: InternPool.Index, | |
| 28 | nav: NavMapIndex, | |
| 29 | uav: UavMapIndex, | |
| 30 | lazy_code: LazyMapRef.Index(.code), | |
| 31 | lazy_const_data: LazyMapRef.Index(.const_data), | |
| 32 | ||
| 33 | pub const NavMapIndex = enum(u32) { | |
| 34 | _, | |
| 35 | ||
| 36 | pub fn navIndex(nmi: NavMapIndex, elf: *const Elf) InternPool.Nav.Index { | |
| 37 | return elf.navs.keys()[@intFromEnum(nmi)]; | |
| 38 | } | |
| 39 | ||
| 40 | pub fn symbol(nmi: NavMapIndex, elf: *const Elf) Symbol.Index { | |
| 41 | return elf.navs.values()[@intFromEnum(nmi)]; | |
| 42 | } | |
| 43 | }; | |
| 44 | ||
| 45 | pub const UavMapIndex = enum(u32) { | |
| 46 | _, | |
| 47 | ||
| 48 | pub fn uavValue(umi: UavMapIndex, elf: *const Elf) InternPool.Index { | |
| 49 | return elf.uavs.keys()[@intFromEnum(umi)]; | |
| 50 | } | |
| 51 | ||
| 52 | pub fn symbol(umi: UavMapIndex, elf: *const Elf) Symbol.Index { | |
| 53 | return elf.uavs.values()[@intFromEnum(umi)]; | |
| 54 | } | |
| 55 | }; | |
| 56 | ||
| 57 | pub const LazyMapRef = struct { | |
| 58 | kind: link.File.LazySymbol.Kind, | |
| 59 | index: u32, | |
| 60 | ||
| 61 | pub fn Index(comptime kind: link.File.LazySymbol.Kind) type { | |
| 62 | return enum(u32) { | |
| 63 | _, | |
| 64 | ||
| 65 | pub fn ref(lmi: @This()) LazyMapRef { | |
| 66 | return .{ .kind = kind, .index = @intFromEnum(lmi) }; | |
| 67 | } | |
| 68 | ||
| 69 | pub fn lazySymbol(lmi: @This(), elf: *const Elf) link.File.LazySymbol { | |
| 70 | return lmi.ref().lazySymbol(elf); | |
| 71 | } | |
| 72 | ||
| 73 | pub fn symbol(lmi: @This(), elf: *const Elf) Symbol.Index { | |
| 74 | return lmi.ref().symbol(elf); | |
| 75 | } | |
| 76 | }; | |
| 77 | } | |
| 78 | ||
| 79 | pub fn lazySymbol(lmr: LazyMapRef, elf: *const Elf) link.File.LazySymbol { | |
| 80 | return .{ .kind = lmr.kind, .ty = elf.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] }; | |
| 81 | } | |
| 82 | ||
| 83 | pub fn symbol(lmr: LazyMapRef, elf: *const Elf) Symbol.Index { | |
| 84 | return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index]; | |
| 85 | } | |
| 86 | }; | |
| 32 | 87 | |
| 33 | 88 | pub const Tag = @typeInfo(Node).@"union".tag_type.?; |
| 34 | 89 | |
| ... | ... | @@ -43,11 +98,7 @@ pub const Node = union(enum) { |
| 43 | 98 | seg_text, |
| 44 | 99 | seg_data, |
| 45 | 100 | }; |
| 46 | var mut_known: std.enums.EnumFieldStruct( | |
| 47 | Known, | |
| 48 | MappedFile.Node.Index, | |
| 49 | null, | |
| 50 | ) = undefined; | |
| 101 | var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined; | |
| 51 | 102 | for (@typeInfo(Known).@"enum".fields) |field| |
| 52 | 103 | @field(mut_known, field.name) = @enumFromInt(field.value); |
| 53 | 104 | break :known mut_known; |
| ... | ... | @@ -223,10 +274,10 @@ pub const Reloc = extern struct { |
| 223 | 274 | addend: i64, |
| 224 | 275 | |
| 225 | 276 | pub const Type = extern union { |
| 226 | x86_64: std.elf.R_X86_64, | |
| 227 | aarch64: std.elf.R_AARCH64, | |
| 228 | riscv: std.elf.R_RISCV, | |
| 229 | ppc64: std.elf.R_PPC64, | |
| 277 | X86_64: std.elf.R_X86_64, | |
| 278 | AARCH64: std.elf.R_AARCH64, | |
| 279 | RISCV: std.elf.R_RISCV, | |
| 280 | PPC64: std.elf.R_PPC64, | |
| 230 | 281 | }; |
| 231 | 282 | |
| 232 | 283 | pub const Index = enum(u32) { |
| ... | ... | @@ -239,7 +290,7 @@ pub const Reloc = extern struct { |
| 239 | 290 | }; |
| 240 | 291 | |
| 241 | 292 | pub fn apply(reloc: *const Reloc, elf: *Elf) void { |
| 242 | const target_endian = elf.endian(); | |
| 293 | const target_endian = elf.targetEndian(); | |
| 243 | 294 | switch (reloc.loc.get(elf).ni) { |
| 244 | 295 | .none => return, |
| 245 | 296 | else => |ni| if (ni.hasMoved(&elf.mf)) return, |
| ... | ... | @@ -274,7 +325,7 @@ pub const Reloc = extern struct { |
| 274 | 325 | ) +% @as(u64, @bitCast(reloc.addend)); |
| 275 | 326 | switch (elf.ehdrField(.machine)) { |
| 276 | 327 | else => |machine| @panic(@tagName(machine)), |
| 277 | .X86_64 => switch (reloc.type.x86_64) { | |
| 328 | .X86_64 => switch (reloc.type.X86_64) { | |
| 278 | 329 | else => |kind| @panic(@tagName(kind)), |
| 279 | 330 | .@"64" => std.mem.writeInt( |
| 280 | 331 | u64, |
| ... | ... | @@ -394,37 +445,7 @@ fn create( |
| 394 | 445 | }, |
| 395 | 446 | .Obj => .REL, |
| 396 | 447 | }; |
| 397 | const machine: std.elf.EM = switch (target.cpu.arch) { | |
| 398 | .spirv32, .spirv64, .wasm32, .wasm64 => .NONE, | |
| 399 | .sparc => .SPARC, | |
| 400 | .x86 => .@"386", | |
| 401 | .m68k => .@"68K", | |
| 402 | .mips, .mipsel, .mips64, .mips64el => .MIPS, | |
| 403 | .powerpc, .powerpcle => .PPC, | |
| 404 | .powerpc64, .powerpc64le => .PPC64, | |
| 405 | .s390x => .S390, | |
| 406 | .arm, .armeb, .thumb, .thumbeb => .ARM, | |
| 407 | .hexagon => .SH, | |
| 408 | .sparc64 => .SPARCV9, | |
| 409 | .arc => .ARC, | |
| 410 | .x86_64 => .X86_64, | |
| 411 | .or1k => .OR1K, | |
| 412 | .xtensa => .XTENSA, | |
| 413 | .msp430 => .MSP430, | |
| 414 | .avr => .AVR, | |
| 415 | .nvptx, .nvptx64 => .CUDA, | |
| 416 | .kalimba => .CSR_KALIMBA, | |
| 417 | .aarch64, .aarch64_be => .AARCH64, | |
| 418 | .xcore => .XCORE, | |
| 419 | .amdgcn => .AMDGPU, | |
| 420 | .riscv32, .riscv32be, .riscv64, .riscv64be => .RISCV, | |
| 421 | .lanai => .LANAI, | |
| 422 | .bpfel, .bpfeb => .BPF, | |
| 423 | .ve => .VE, | |
| 424 | .csky => .CSKY, | |
| 425 | .loongarch32, .loongarch64 => .LOONGARCH, | |
| 426 | .propeller => if (target.cpu.has(.propeller, .p2)) .PROPELLER2 else .PROPELLER, | |
| 427 | }; | |
| 448 | const machine = target.toElfMachine(); | |
| 428 | 449 | const maybe_interp = switch (comp.config.output_mode) { |
| 429 | 450 | .Exe, .Lib => switch (comp.config.link_mode) { |
| 430 | 451 | .static => null, |
| ... | ... | @@ -479,7 +500,7 @@ fn create( |
| 479 | 500 | |
| 480 | 501 | switch (class) { |
| 481 | 502 | .NONE, _ => unreachable, |
| 482 | inline .@"32", .@"64" => |ct_class| try elf.initHeaders( | |
| 503 | inline else => |ct_class| try elf.initHeaders( | |
| 483 | 504 | ct_class, |
| 484 | 505 | data, |
| 485 | 506 | osabi, |
| ... | ... | @@ -567,30 +588,31 @@ fn initHeaders( |
| 567 | 588 | .fixed = true, |
| 568 | 589 | })); |
| 569 | 590 | elf.nodes.appendAssumeCapacity(.ehdr); |
| 570 | ||
| 571 | const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf))); | |
| 572 | const EI = std.elf.EI; | |
| 573 | @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); | |
| 574 | ehdr.ident[EI.CLASS] = @intFromEnum(class); | |
| 575 | ehdr.ident[EI.DATA] = @intFromEnum(data); | |
| 576 | ehdr.ident[EI.VERSION] = 1; | |
| 577 | ehdr.ident[EI.OSABI] = @intFromEnum(osabi); | |
| 578 | ehdr.ident[EI.ABIVERSION] = 0; | |
| 579 | @memset(ehdr.ident[EI.PAD..], 0); | |
| 580 | ehdr.type = @"type"; | |
| 581 | ehdr.machine = machine; | |
| 582 | ehdr.version = 1; | |
| 583 | ehdr.entry = 0; | |
| 584 | ehdr.phoff = 0; | |
| 585 | ehdr.shoff = 0; | |
| 586 | ehdr.flags = 0; | |
| 587 | ehdr.ehsize = @sizeOf(ElfN.Ehdr); | |
| 588 | ehdr.phentsize = @sizeOf(ElfN.Phdr); | |
| 589 | ehdr.phnum = @min(phnum, std.elf.PN_XNUM); | |
| 590 | ehdr.shentsize = @sizeOf(ElfN.Shdr); | |
| 591 | ehdr.shnum = 1; | |
| 592 | ehdr.shstrndx = 0; | |
| 593 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); | |
| 591 | { | |
| 592 | const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf))); | |
| 593 | const EI = std.elf.EI; | |
| 594 | @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); | |
| 595 | ehdr.ident[EI.CLASS] = @intFromEnum(class); | |
| 596 | ehdr.ident[EI.DATA] = @intFromEnum(data); | |
| 597 | ehdr.ident[EI.VERSION] = 1; | |
| 598 | ehdr.ident[EI.OSABI] = @intFromEnum(osabi); | |
| 599 | ehdr.ident[EI.ABIVERSION] = 0; | |
| 600 | @memset(ehdr.ident[EI.PAD..], 0); | |
| 601 | ehdr.type = @"type"; | |
| 602 | ehdr.machine = machine; | |
| 603 | ehdr.version = 1; | |
| 604 | ehdr.entry = 0; | |
| 605 | ehdr.phoff = 0; | |
| 606 | ehdr.shoff = 0; | |
| 607 | ehdr.flags = 0; | |
| 608 | ehdr.ehsize = @sizeOf(ElfN.Ehdr); | |
| 609 | ehdr.phentsize = @sizeOf(ElfN.Phdr); | |
| 610 | ehdr.phnum = @min(phnum, std.elf.PN_XNUM); | |
| 611 | ehdr.shentsize = @sizeOf(ElfN.Shdr); | |
| 612 | ehdr.shnum = 1; | |
| 613 | ehdr.shstrndx = 0; | |
| 614 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); | |
| 615 | } | |
| 594 | 616 | |
| 595 | 617 | const phdr_ni = Node.known.phdr; |
| 596 | 618 | assert(phdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ |
| ... | ... | @@ -750,7 +772,10 @@ fn initHeaders( |
| 750 | 772 | }, |
| 751 | 773 | .shndx = std.elf.SHN_UNDEF, |
| 752 | 774 | }; |
| 753 | ehdr.shstrndx = ehdr.shnum; | |
| 775 | { | |
| 776 | const ehdr = @field(elf.ehdrPtr(), @tagName(class)); | |
| 777 | ehdr.shstrndx = ehdr.shnum; | |
| 778 | } | |
| 754 | 779 | assert(try elf.addSection(seg_rodata_ni, .{ |
| 755 | 780 | .type = std.elf.SHT_STRTAB, |
| 756 | 781 | .addralign = elf.mf.flags.block_size, |
| ... | ... | @@ -821,6 +846,24 @@ fn getNode(elf: *Elf, ni: MappedFile.Node.Index) Node { |
| 821 | 846 | return elf.nodes.get(@intFromEnum(ni)); |
| 822 | 847 | } |
| 823 | 848 | |
| 849 | pub fn identClass(elf: *Elf) std.elf.CLASS { | |
| 850 | return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]); | |
| 851 | } | |
| 852 | ||
| 853 | pub fn identData(elf: *Elf) std.elf.DATA { | |
| 854 | return @enumFromInt(elf.mf.contents[std.elf.EI.DATA]); | |
| 855 | } | |
| 856 | fn endianForData(data: std.elf.DATA) std.builtin.Endian { | |
| 857 | return switch (data) { | |
| 858 | .NONE, _ => unreachable, | |
| 859 | .@"2LSB" => .little, | |
| 860 | .@"2MSB" => .big, | |
| 861 | }; | |
| 862 | } | |
| 863 | pub fn targetEndian(elf: *Elf) std.builtin.Endian { | |
| 864 | return endianForData(elf.identData()); | |
| 865 | } | |
| 866 | ||
| 824 | 867 | pub const EhdrPtr = union(std.elf.CLASS) { |
| 825 | 868 | NONE: noreturn, |
| 826 | 869 | @"32": *std.elf.Elf32.Ehdr, |
| ... | ... | @@ -830,7 +873,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr { |
| 830 | 873 | const slice = Node.known.ehdr.slice(&elf.mf); |
| 831 | 874 | return switch (elf.identClass()) { |
| 832 | 875 | .NONE, _ => unreachable, |
| 833 | inline .@"32", .@"64" => |class| @unionInit( | |
| 876 | inline else => |class| @unionInit( | |
| 834 | 877 | EhdrPtr, |
| 835 | 878 | @tagName(class), |
| 836 | 879 | @ptrCast(@alignCast(slice)), |
| ... | ... | @@ -841,35 +884,15 @@ pub fn ehdrField( |
| 841 | 884 | elf: *Elf, |
| 842 | 885 | comptime field: enum { type, machine }, |
| 843 | 886 | ) @FieldType(std.elf.Elf32.Ehdr, @tagName(field)) { |
| 844 | const Field = @FieldType(std.elf.Elf32.Ehdr, @tagName(field)); | |
| 845 | comptime assert(@FieldType(std.elf.Elf64.Ehdr, @tagName(field)) == Field); | |
| 846 | 887 | return @enumFromInt(std.mem.toNative( |
| 847 | @typeInfo(Field).@"enum".tag_type, | |
| 888 | @typeInfo(@FieldType(std.elf.Elf32.Ehdr, @tagName(field))).@"enum".tag_type, | |
| 848 | 889 | @intFromEnum(switch (elf.ehdrPtr()) { |
| 849 | 890 | inline else => |ehdr| @field(ehdr, @tagName(field)), |
| 850 | 891 | }), |
| 851 | elf.endian(), | |
| 892 | elf.targetEndian(), | |
| 852 | 893 | )); |
| 853 | 894 | } |
| 854 | 895 | |
| 855 | pub fn identClass(elf: *Elf) std.elf.CLASS { | |
| 856 | return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]); | |
| 857 | } | |
| 858 | ||
| 859 | pub fn identData(elf: *Elf) std.elf.DATA { | |
| 860 | return @enumFromInt(elf.mf.contents[std.elf.EI.DATA]); | |
| 861 | } | |
| 862 | fn endianForData(data: std.elf.DATA) std.builtin.Endian { | |
| 863 | return switch (data) { | |
| 864 | .NONE, _ => unreachable, | |
| 865 | .@"2LSB" => .little, | |
| 866 | .@"2MSB" => .big, | |
| 867 | }; | |
| 868 | } | |
| 869 | pub fn endian(elf: *Elf) std.builtin.Endian { | |
| 870 | return endianForData(elf.identData()); | |
| 871 | } | |
| 872 | ||
| 873 | 896 | fn baseAddrForType(@"type": std.elf.ET) u64 { |
| 874 | 897 | return switch (@"type") { |
| 875 | 898 | else => 0, |
| ... | ... | @@ -889,7 +912,7 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice { |
| 889 | 912 | const slice = Node.known.phdr.slice(&elf.mf); |
| 890 | 913 | return switch (elf.identClass()) { |
| 891 | 914 | .NONE, _ => unreachable, |
| 892 | inline .@"32", .@"64" => |class| @unionInit( | |
| 915 | inline else => |class| @unionInit( | |
| 893 | 916 | PhdrSlice, |
| 894 | 917 | @tagName(class), |
| 895 | 918 | @ptrCast(@alignCast(slice)), |
| ... | ... | @@ -906,7 +929,7 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice { |
| 906 | 929 | const slice = Node.known.shdr.slice(&elf.mf); |
| 907 | 930 | return switch (elf.identClass()) { |
| 908 | 931 | .NONE, _ => unreachable, |
| 909 | inline .@"32", .@"64" => |class| @unionInit( | |
| 932 | inline else => |class| @unionInit( | |
| 910 | 933 | ShdrSlice, |
| 911 | 934 | @tagName(class), |
| 912 | 935 | @ptrCast(@alignCast(slice)), |
| ... | ... | @@ -923,7 +946,7 @@ pub fn symSlice(elf: *Elf) SymSlice { |
| 923 | 946 | const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf); |
| 924 | 947 | return switch (elf.identClass()) { |
| 925 | 948 | .NONE, _ => unreachable, |
| 926 | inline .@"32", .@"64" => |class| @unionInit( | |
| 949 | inline else => |class| @unionInit( | |
| 927 | 950 | SymSlice, |
| 928 | 951 | @tagName(class), |
| 929 | 952 | @ptrCast(@alignCast(slice)), |
| ... | ... | @@ -942,7 +965,7 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr { |
| 942 | 965 | }; |
| 943 | 966 | } |
| 944 | 967 | |
| 945 | fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index { | |
| 968 | fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index { | |
| 946 | 969 | defer elf.symtab.addOneAssumeCapacity().* = .{ |
| 947 | 970 | .ni = .none, |
| 948 | 971 | .loc_relocs = .none, |
| ... | ... | @@ -953,30 +976,27 @@ fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index { |
| 953 | 976 | } |
| 954 | 977 | |
| 955 | 978 | fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index { |
| 956 | const si = try elf.addSymbolAssumeCapacity(); | |
| 979 | const si = elf.addSymbolAssumeCapacity(); | |
| 957 | 980 | try si.init(elf, opts); |
| 958 | 981 | return si; |
| 959 | 982 | } |
| 960 | 983 | |
| 961 | pub fn globalSymbol( | |
| 962 | elf: *Elf, | |
| 963 | opts: struct { | |
| 964 | name: []const u8, | |
| 965 | type: std.elf.STT, | |
| 966 | bind: std.elf.STB = .GLOBAL, | |
| 967 | visibility: std.elf.STV = .DEFAULT, | |
| 968 | }, | |
| 969 | ) !Symbol.Index { | |
| 984 | pub fn globalSymbol(elf: *Elf, opts: struct { | |
| 985 | name: []const u8, | |
| 986 | type: std.elf.STT, | |
| 987 | bind: std.elf.STB = .GLOBAL, | |
| 988 | visibility: std.elf.STV = .DEFAULT, | |
| 989 | }) !Symbol.Index { | |
| 970 | 990 | const gpa = elf.base.comp.gpa; |
| 971 | 991 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 972 | const sym_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name)); | |
| 973 | if (!sym_gop.found_existing) sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | |
| 992 | const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name)); | |
| 993 | if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | |
| 974 | 994 | .name = opts.name, |
| 975 | 995 | .type = opts.type, |
| 976 | 996 | .bind = opts.bind, |
| 977 | 997 | .visibility = opts.visibility, |
| 978 | 998 | }); |
| 979 | return sym_gop.value_ptr.*; | |
| 999 | return global_gop.value_ptr.*; | |
| 980 | 1000 | } |
| 981 | 1001 | |
| 982 | 1002 | fn navType( |
| ... | ... | @@ -1008,8 +1028,19 @@ fn navType( |
| 1008 | 1028 | }, |
| 1009 | 1029 | }; |
| 1010 | 1030 | } |
| 1011 | pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { | |
| 1031 | fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { | |
| 1012 | 1032 | const gpa = zcu.gpa; |
| 1033 | const ip = &zcu.intern_pool; | |
| 1034 | const nav = ip.getNav(nav_index); | |
| 1035 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | |
| 1036 | const nav_gop = try elf.navs.getOrPut(gpa, nav_index); | |
| 1037 | if (!nav_gop.found_existing) nav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | |
| 1038 | .name = nav.fqn.toSlice(ip), | |
| 1039 | .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), | |
| 1040 | }); | |
| 1041 | return @enumFromInt(nav_gop.index); | |
| 1042 | } | |
| 1043 | pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { | |
| 1013 | 1044 | const ip = &zcu.intern_pool; |
| 1014 | 1045 | const nav = ip.getNav(nav_index); |
| 1015 | 1046 | if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{ |
| ... | ... | @@ -1027,40 +1058,37 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol. |
| 1027 | 1058 | .protected => .PROTECTED, |
| 1028 | 1059 | }, |
| 1029 | 1060 | }); |
| 1030 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | |
| 1031 | const sym_gop = try elf.navs.getOrPut(gpa, nav_index); | |
| 1032 | if (!sym_gop.found_existing) { | |
| 1033 | sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | |
| 1034 | .name = nav.fqn.toSlice(ip), | |
| 1035 | .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), | |
| 1036 | }); | |
| 1037 | } | |
| 1038 | return sym_gop.value_ptr.*; | |
| 1061 | const nmi = try elf.navMapIndex(zcu, nav_index); | |
| 1062 | return nmi.symbol(elf); | |
| 1039 | 1063 | } |
| 1040 | 1064 | |
| 1041 | pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index { | |
| 1065 | fn uavMapIndex(elf: *Elf, uav_val: InternPool.Index) !Node.UavMapIndex { | |
| 1042 | 1066 | const gpa = elf.base.comp.gpa; |
| 1043 | 1067 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 1044 | const sym_gop = try elf.uavs.getOrPut(gpa, uav_val); | |
| 1045 | if (!sym_gop.found_existing) | |
| 1046 | sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT }); | |
| 1047 | return sym_gop.value_ptr.*; | |
| 1068 | const uav_gop = try elf.uavs.getOrPut(gpa, uav_val); | |
| 1069 | if (!uav_gop.found_existing) | |
| 1070 | uav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT }); | |
| 1071 | return @enumFromInt(uav_gop.index); | |
| 1072 | } | |
| 1073 | pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index { | |
| 1074 | const umi = try elf.uavMapIndex(uav_val); | |
| 1075 | return umi.symbol(elf); | |
| 1048 | 1076 | } |
| 1049 | 1077 | |
| 1050 | 1078 | pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { |
| 1051 | 1079 | const gpa = elf.base.comp.gpa; |
| 1052 | 1080 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 1053 | const sym_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); | |
| 1054 | if (!sym_gop.found_existing) { | |
| 1055 | sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | |
| 1081 | const lazy_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); | |
| 1082 | if (!lazy_gop.found_existing) { | |
| 1083 | lazy_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | |
| 1056 | 1084 | .type = switch (lazy.kind) { |
| 1057 | 1085 | .code => .FUNC, |
| 1058 | 1086 | .const_data => .OBJECT, |
| 1059 | 1087 | }, |
| 1060 | 1088 | }); |
| 1061 | elf.base.comp.link_lazy_prog_node.increaseEstimatedTotalItems(1); | |
| 1089 | elf.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1); | |
| 1062 | 1090 | } |
| 1063 | return sym_gop.value_ptr.*; | |
| 1091 | return lazy_gop.value_ptr.*; | |
| 1064 | 1092 | } |
| 1065 | 1093 | |
| 1066 | 1094 | pub fn getNavVAddr( |
| ... | ... | @@ -1088,7 +1116,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In |
| 1088 | 1116 | reloc_info.addend, |
| 1089 | 1117 | switch (elf.ehdrField(.machine)) { |
| 1090 | 1118 | else => unreachable, |
| 1091 | .X86_64 => .{ .x86_64 = switch (elf.identClass()) { | |
| 1119 | .X86_64 => .{ .X86_64 = switch (elf.identClass()) { | |
| 1092 | 1120 | .NONE, _ => unreachable, |
| 1093 | 1121 | .@"32" => .@"32", |
| 1094 | 1122 | .@"64" => .@"64", |
| ... | ... | @@ -1107,7 +1135,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1107 | 1135 | entsize: std.elf.Word = 0, |
| 1108 | 1136 | }) !Symbol.Index { |
| 1109 | 1137 | const gpa = elf.base.comp.gpa; |
| 1110 | const target_endian = elf.endian(); | |
| 1138 | const target_endian = elf.targetEndian(); | |
| 1111 | 1139 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 1112 | 1140 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 1113 | 1141 | |
| ... | ... | @@ -1127,7 +1155,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1127 | 1155 | .size = opts.size, |
| 1128 | 1156 | .moved = true, |
| 1129 | 1157 | }); |
| 1130 | const si = try elf.addSymbolAssumeCapacity(); | |
| 1158 | const si = elf.addSymbolAssumeCapacity(); | |
| 1131 | 1159 | elf.nodes.appendAssumeCapacity(.{ .section = si }); |
| 1132 | 1160 | si.get(elf).ni = ni; |
| 1133 | 1161 | try si.init(elf, .{ |
| ... | ... | @@ -1160,7 +1188,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1160 | 1188 | fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { |
| 1161 | 1189 | const strtab_entry = try elf.string(.strtab, name); |
| 1162 | 1190 | const shstrtab_entry = try elf.string(.shstrtab, name); |
| 1163 | const target_endian = elf.endian(); | |
| 1191 | const target_endian = elf.targetEndian(); | |
| 1164 | 1192 | switch (elf.shdrSlice()) { |
| 1165 | 1193 | inline else => |shdr, class| { |
| 1166 | 1194 | const sym = @field(elf.symPtr(si), @tagName(class)); |
| ... | ... | @@ -1173,7 +1201,7 @@ fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { |
| 1173 | 1201 | } |
| 1174 | 1202 | |
| 1175 | 1203 | fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { |
| 1176 | const target_endian = elf.endian(); | |
| 1204 | const target_endian = elf.targetEndian(); | |
| 1177 | 1205 | switch (elf.shdrSlice()) { |
| 1178 | 1206 | inline else => |shdr, class| { |
| 1179 | 1207 | const sym = @field(elf.symPtr(si), @tagName(class)); |
| ... | ... | @@ -1184,7 +1212,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { |
| 1184 | 1212 | } |
| 1185 | 1213 | |
| 1186 | 1214 | fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { |
| 1187 | const target_endian = elf.endian(); | |
| 1215 | const target_endian = elf.targetEndian(); | |
| 1188 | 1216 | const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[name: switch (elf.shdrSlice()) { |
| 1189 | 1217 | inline else => |shndx, class| { |
| 1190 | 1218 | const sym = @field(elf.symPtr(si), @tagName(class)); |
| ... | ... | @@ -1263,7 +1291,8 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 1263 | 1291 | }; |
| 1264 | 1292 | if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return; |
| 1265 | 1293 | |
| 1266 | const si = try elf.navSymbol(zcu, nav_index); | |
| 1294 | const nmi = try elf.navMapIndex(zcu, nav_index); | |
| 1295 | const si = nmi.symbol(elf); | |
| 1267 | 1296 | const ni = ni: { |
| 1268 | 1297 | const sym = si.get(elf); |
| 1269 | 1298 | switch (sym.ni) { |
| ... | ... | @@ -1275,7 +1304,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 1275 | 1304 | .alignment = pt.navAlignment(nav_index).toStdMem(), |
| 1276 | 1305 | .moved = true, |
| 1277 | 1306 | }); |
| 1278 | elf.nodes.appendAssumeCapacity(.{ .nav = nav_index }); | |
| 1307 | elf.nodes.appendAssumeCapacity(.{ .nav = nmi }); | |
| 1279 | 1308 | sym.ni = ni; |
| 1280 | 1309 | switch (elf.symPtr(si)) { |
| 1281 | 1310 | inline else => |sym_ptr, class| sym_ptr.shndx = |
| ... | ... | @@ -1289,28 +1318,24 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 1289 | 1318 | break :ni sym.ni; |
| 1290 | 1319 | }; |
| 1291 | 1320 | |
| 1292 | const size = size: { | |
| 1293 | var nw: MappedFile.Node.Writer = undefined; | |
| 1294 | ni.writer(&elf.mf, gpa, &nw); | |
| 1295 | defer nw.deinit(); | |
| 1296 | codegen.generateSymbol( | |
| 1297 | &elf.base, | |
| 1298 | pt, | |
| 1299 | zcu.navSrcLoc(nav_index), | |
| 1300 | .fromInterned(nav_init), | |
| 1301 | &nw.interface, | |
| 1302 | .{ .atom_index = @intFromEnum(si) }, | |
| 1303 | ) catch |err| switch (err) { | |
| 1304 | error.WriteFailed => return error.OutOfMemory, | |
| 1305 | else => |e| return e, | |
| 1306 | }; | |
| 1307 | break :size nw.interface.end; | |
| 1321 | var nw: MappedFile.Node.Writer = undefined; | |
| 1322 | ni.writer(&elf.mf, gpa, &nw); | |
| 1323 | defer nw.deinit(); | |
| 1324 | codegen.generateSymbol( | |
| 1325 | &elf.base, | |
| 1326 | pt, | |
| 1327 | zcu.navSrcLoc(nav_index), | |
| 1328 | .fromInterned(nav_init), | |
| 1329 | &nw.interface, | |
| 1330 | .{ .atom_index = @intFromEnum(si) }, | |
| 1331 | ) catch |err| switch (err) { | |
| 1332 | error.WriteFailed => return error.OutOfMemory, | |
| 1333 | else => |e| return e, | |
| 1308 | 1334 | }; |
| 1309 | ||
| 1310 | const target_endian = elf.endian(); | |
| 1335 | const target_endian = elf.targetEndian(); | |
| 1311 | 1336 | switch (elf.symPtr(si)) { |
| 1312 | 1337 | inline else => |sym| sym.size = |
| 1313 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), | |
| 1338 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian), | |
| 1314 | 1339 | } |
| 1315 | 1340 | si.applyLocationRelocs(elf); |
| 1316 | 1341 | } |
| ... | ... | @@ -1326,7 +1351,7 @@ pub fn lowerUav( |
| 1326 | 1351 | const gpa = zcu.gpa; |
| 1327 | 1352 | |
| 1328 | 1353 | try elf.pending_uavs.ensureUnusedCapacity(gpa, 1); |
| 1329 | const si = elf.uavSymbol(uav_val) catch |err| switch (err) { | |
| 1354 | const umi = elf.uavMapIndex(uav_val) catch |err| switch (err) { | |
| 1330 | 1355 | error.OutOfMemory => return error.OutOfMemory, |
| 1331 | 1356 | else => |e| return .{ .fail = try Zcu.ErrorMsg.create( |
| 1332 | 1357 | gpa, |
| ... | ... | @@ -1335,11 +1360,12 @@ pub fn lowerUav( |
| 1335 | 1360 | .{@errorName(e)}, |
| 1336 | 1361 | ) }, |
| 1337 | 1362 | }; |
| 1363 | const si = umi.symbol(elf); | |
| 1338 | 1364 | if (switch (si.get(elf).ni) { |
| 1339 | 1365 | .none => true, |
| 1340 | 1366 | else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt), |
| 1341 | 1367 | }) { |
| 1342 | const gop = elf.pending_uavs.getOrPutAssumeCapacity(uav_val); | |
| 1368 | const gop = elf.pending_uavs.getOrPutAssumeCapacity(umi); | |
| 1343 | 1369 | if (gop.found_existing) { |
| 1344 | 1370 | gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align); |
| 1345 | 1371 | } else { |
| ... | ... | @@ -1347,7 +1373,7 @@ pub fn lowerUav( |
| 1347 | 1373 | .alignment = uav_align, |
| 1348 | 1374 | .src_loc = src_loc, |
| 1349 | 1375 | }; |
| 1350 | elf.base.comp.link_uav_prog_node.increaseEstimatedTotalItems(1); | |
| 1376 | elf.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1); | |
| 1351 | 1377 | } |
| 1352 | 1378 | } |
| 1353 | 1379 | return .{ .sym_index = @intFromEnum(si) }; |
| ... | ... | @@ -1384,7 +1410,8 @@ fn updateFuncInner( |
| 1384 | 1410 | const func = zcu.funcInfo(func_index); |
| 1385 | 1411 | const nav = ip.getNav(func.owner_nav); |
| 1386 | 1412 | |
| 1387 | const si = try elf.navSymbol(zcu, func.owner_nav); | |
| 1413 | const nmi = try elf.navMapIndex(zcu, func.owner_nav); | |
| 1414 | const si = nmi.symbol(elf); | |
| 1388 | 1415 | log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si }); |
| 1389 | 1416 | const ni = ni: { |
| 1390 | 1417 | const sym = si.get(elf); |
| ... | ... | @@ -1406,7 +1433,7 @@ fn updateFuncInner( |
| 1406 | 1433 | }.toStdMem(), |
| 1407 | 1434 | .moved = true, |
| 1408 | 1435 | }); |
| 1409 | elf.nodes.appendAssumeCapacity(.{ .nav = func.owner_nav }); | |
| 1436 | elf.nodes.appendAssumeCapacity(.{ .nav = nmi }); | |
| 1410 | 1437 | sym.ni = ni; |
| 1411 | 1438 | switch (elf.symPtr(si)) { |
| 1412 | 1439 | inline else => |sym_ptr, class| sym_ptr.shndx = |
| ... | ... | @@ -1420,37 +1447,35 @@ fn updateFuncInner( |
| 1420 | 1447 | break :ni sym.ni; |
| 1421 | 1448 | }; |
| 1422 | 1449 | |
| 1423 | const size = size: { | |
| 1424 | var nw: MappedFile.Node.Writer = undefined; | |
| 1425 | ni.writer(&elf.mf, gpa, &nw); | |
| 1426 | defer nw.deinit(); | |
| 1427 | codegen.emitFunction( | |
| 1428 | &elf.base, | |
| 1429 | pt, | |
| 1430 | zcu.navSrcLoc(func.owner_nav), | |
| 1431 | func_index, | |
| 1432 | @intFromEnum(si), | |
| 1433 | mir, | |
| 1434 | &nw.interface, | |
| 1435 | .none, | |
| 1436 | ) catch |err| switch (err) { | |
| 1437 | error.WriteFailed => return nw.err.?, | |
| 1438 | else => |e| return e, | |
| 1439 | }; | |
| 1440 | break :size nw.interface.end; | |
| 1450 | var nw: MappedFile.Node.Writer = undefined; | |
| 1451 | ni.writer(&elf.mf, gpa, &nw); | |
| 1452 | defer nw.deinit(); | |
| 1453 | codegen.emitFunction( | |
| 1454 | &elf.base, | |
| 1455 | pt, | |
| 1456 | zcu.navSrcLoc(func.owner_nav), | |
| 1457 | func_index, | |
| 1458 | @intFromEnum(si), | |
| 1459 | mir, | |
| 1460 | &nw.interface, | |
| 1461 | .none, | |
| 1462 | ) catch |err| switch (err) { | |
| 1463 | error.WriteFailed => return nw.err.?, | |
| 1464 | else => |e| return e, | |
| 1441 | 1465 | }; |
| 1442 | ||
| 1443 | const target_endian = elf.endian(); | |
| 1466 | const target_endian = elf.targetEndian(); | |
| 1444 | 1467 | switch (elf.symPtr(si)) { |
| 1445 | 1468 | inline else => |sym| sym.size = |
| 1446 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), | |
| 1469 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian), | |
| 1447 | 1470 | } |
| 1448 | 1471 | si.applyLocationRelocs(elf); |
| 1449 | 1472 | } |
| 1450 | 1473 | |
| 1451 | 1474 | pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void { |
| 1452 | const si = elf.lazy.getPtr(.const_data).map.get(.anyerror_type) orelse return; | |
| 1453 | elf.flushLazy(pt, .{ .kind = .const_data, .ty = .anyerror_type }, si) catch |err| switch (err) { | |
| 1475 | elf.flushLazy(pt, .{ | |
| 1476 | .kind = .const_data, | |
| 1477 | .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return), | |
| 1478 | }) catch |err| switch (err) { | |
| 1454 | 1479 | error.OutOfMemory => return error.OutOfMemory, |
| 1455 | 1480 | error.CodegenFail => return error.LinkFailure, |
| 1456 | 1481 | else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}), |
| ... | ... | @@ -1472,14 +1497,13 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1472 | 1497 | const comp = elf.base.comp; |
| 1473 | 1498 | task: { |
| 1474 | 1499 | while (elf.pending_uavs.pop()) |pending_uav| { |
| 1475 | const sub_prog_node = | |
| 1476 | elf.idleProgNode( | |
| 1477 | tid, | |
| 1478 | comp.link_uav_prog_node, | |
| 1479 | .{ .uav = pending_uav.key }, | |
| 1480 | ); | |
| 1500 | const sub_prog_node = elf.idleProgNode( | |
| 1501 | tid, | |
| 1502 | comp.link_const_prog_node, | |
| 1503 | .{ .uav = pending_uav.key }, | |
| 1504 | ); | |
| 1481 | 1505 | defer sub_prog_node.end(); |
| 1482 | break :task elf.flushUav( | |
| 1506 | elf.flushUav( | |
| 1483 | 1507 | .{ .zcu = elf.base.comp.zcu.?, .tid = tid }, |
| 1484 | 1508 | pending_uav.key, |
| 1485 | 1509 | pending_uav.value.alignment, |
| ... | ... | @@ -1491,37 +1515,34 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1491 | 1515 | .{e}, |
| 1492 | 1516 | ), |
| 1493 | 1517 | }; |
| 1518 | break :task; | |
| 1494 | 1519 | } |
| 1495 | 1520 | var lazy_it = elf.lazy.iterator(); |
| 1496 | while (lazy_it.next()) |lazy| for ( | |
| 1497 | lazy.value.map.keys()[lazy.value.pending_index..], | |
| 1498 | lazy.value.map.values()[lazy.value.pending_index..], | |
| 1499 | ) |ty, si| { | |
| 1500 | lazy.value.pending_index += 1; | |
| 1521 | while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { | |
| 1501 | 1522 | const pt: Zcu.PerThread = .{ .zcu = elf.base.comp.zcu.?, .tid = tid }; |
| 1502 | const kind = switch (lazy.key) { | |
| 1523 | const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; | |
| 1524 | lazy.value.pending_index += 1; | |
| 1525 | const kind = switch (lmr.kind) { | |
| 1503 | 1526 | .code => "code", |
| 1504 | 1527 | .const_data => "data", |
| 1505 | 1528 | }; |
| 1506 | 1529 | var name: [std.Progress.Node.max_name_len]u8 = undefined; |
| 1507 | const sub_prog_node = comp.link_lazy_prog_node.start( | |
| 1530 | const sub_prog_node = comp.link_synth_prog_node.start( | |
| 1508 | 1531 | std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ |
| 1509 | 1532 | kind, |
| 1510 | Type.fromInterned(ty).fmt(pt), | |
| 1533 | Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt), | |
| 1511 | 1534 | }) catch &name, |
| 1512 | 1535 | 0, |
| 1513 | 1536 | ); |
| 1514 | 1537 | defer sub_prog_node.end(); |
| 1515 | break :task elf.flushLazy(pt, .{ | |
| 1516 | .kind = lazy.key, | |
| 1517 | .ty = ty, | |
| 1518 | }, si) catch |err| switch (err) { | |
| 1538 | elf.flushLazy(pt, lmr) catch |err| switch (err) { | |
| 1519 | 1539 | error.OutOfMemory => return error.OutOfMemory, |
| 1520 | 1540 | else => |e| return elf.base.comp.link_diags.fail( |
| 1521 | 1541 | "linker failed to lower lazy {s}: {t}", |
| 1522 | 1542 | .{ kind, e }, |
| 1523 | 1543 | ), |
| 1524 | 1544 | }; |
| 1545 | break :task; | |
| 1525 | 1546 | }; |
| 1526 | 1547 | while (elf.mf.updates.pop()) |ni| { |
| 1527 | 1548 | const clean_moved = ni.cleanMoved(&elf.mf); |
| ... | ... | @@ -1551,12 +1572,12 @@ fn idleProgNode( |
| 1551 | 1572 | return prog_node.start(name: switch (node) { |
| 1552 | 1573 | else => |tag| @tagName(tag), |
| 1553 | 1574 | .section => |si| elf.sectionName(si), |
| 1554 | .nav => |nav| { | |
| 1575 | .nav => |nmi| { | |
| 1555 | 1576 | const ip = &elf.base.comp.zcu.?.intern_pool; |
| 1556 | break :name ip.getNav(nav).fqn.toSlice(ip); | |
| 1577 | break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip); | |
| 1557 | 1578 | }, |
| 1558 | .uav => |uav| std.fmt.bufPrint(&name, "{f}", .{ | |
| 1559 | Value.fromInterned(uav).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), | |
| 1579 | .uav => |umi| std.fmt.bufPrint(&name, "{f}", .{ | |
| 1580 | Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), | |
| 1560 | 1581 | }) catch &name, |
| 1561 | 1582 | }, 0); |
| 1562 | 1583 | } |
| ... | ... | @@ -1564,14 +1585,15 @@ fn idleProgNode( |
| 1564 | 1585 | fn flushUav( |
| 1565 | 1586 | elf: *Elf, |
| 1566 | 1587 | pt: Zcu.PerThread, |
| 1567 | uav_val: InternPool.Index, | |
| 1588 | umi: Node.UavMapIndex, | |
| 1568 | 1589 | uav_align: InternPool.Alignment, |
| 1569 | 1590 | src_loc: Zcu.LazySrcLoc, |
| 1570 | 1591 | ) !void { |
| 1571 | 1592 | const zcu = pt.zcu; |
| 1572 | 1593 | const gpa = zcu.gpa; |
| 1573 | 1594 | |
| 1574 | const si = try elf.uavSymbol(uav_val); | |
| 1595 | const uav_val = umi.uavValue(elf); | |
| 1596 | const si = umi.symbol(elf); | |
| 1575 | 1597 | const ni = ni: { |
| 1576 | 1598 | const sym = si.get(elf); |
| 1577 | 1599 | switch (sym.ni) { |
| ... | ... | @@ -1581,7 +1603,7 @@ fn flushUav( |
| 1581 | 1603 | .alignment = uav_align.toStdMem(), |
| 1582 | 1604 | .moved = true, |
| 1583 | 1605 | }); |
| 1584 | elf.nodes.appendAssumeCapacity(.{ .uav = uav_val }); | |
| 1606 | elf.nodes.appendAssumeCapacity(.{ .uav = umi }); | |
| 1585 | 1607 | sym.ni = ni; |
| 1586 | 1608 | switch (elf.symPtr(si)) { |
| 1587 | 1609 | inline else => |sym_ptr, class| sym_ptr.shndx = |
| ... | ... | @@ -1598,36 +1620,34 @@ fn flushUav( |
| 1598 | 1620 | break :ni sym.ni; |
| 1599 | 1621 | }; |
| 1600 | 1622 | |
| 1601 | const size = size: { | |
| 1602 | var nw: MappedFile.Node.Writer = undefined; | |
| 1603 | ni.writer(&elf.mf, gpa, &nw); | |
| 1604 | defer nw.deinit(); | |
| 1605 | codegen.generateSymbol( | |
| 1606 | &elf.base, | |
| 1607 | pt, | |
| 1608 | src_loc, | |
| 1609 | .fromInterned(uav_val), | |
| 1610 | &nw.interface, | |
| 1611 | .{ .atom_index = @intFromEnum(si) }, | |
| 1612 | ) catch |err| switch (err) { | |
| 1613 | error.WriteFailed => return error.OutOfMemory, | |
| 1614 | else => |e| return e, | |
| 1615 | }; | |
| 1616 | break :size nw.interface.end; | |
| 1623 | var nw: MappedFile.Node.Writer = undefined; | |
| 1624 | ni.writer(&elf.mf, gpa, &nw); | |
| 1625 | defer nw.deinit(); | |
| 1626 | codegen.generateSymbol( | |
| 1627 | &elf.base, | |
| 1628 | pt, | |
| 1629 | src_loc, | |
| 1630 | .fromInterned(uav_val), | |
| 1631 | &nw.interface, | |
| 1632 | .{ .atom_index = @intFromEnum(si) }, | |
| 1633 | ) catch |err| switch (err) { | |
| 1634 | error.WriteFailed => return error.OutOfMemory, | |
| 1635 | else => |e| return e, | |
| 1617 | 1636 | }; |
| 1618 | ||
| 1619 | const target_endian = elf.endian(); | |
| 1637 | const target_endian = elf.targetEndian(); | |
| 1620 | 1638 | switch (elf.symPtr(si)) { |
| 1621 | 1639 | inline else => |sym| sym.size = |
| 1622 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), | |
| 1640 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian), | |
| 1623 | 1641 | } |
| 1624 | 1642 | si.applyLocationRelocs(elf); |
| 1625 | 1643 | } |
| 1626 | 1644 | |
| 1627 | fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbol.Index) !void { | |
| 1645 | fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | |
| 1628 | 1646 | const zcu = pt.zcu; |
| 1629 | 1647 | const gpa = zcu.gpa; |
| 1630 | 1648 | |
| 1649 | const lazy = lmr.lazySymbol(elf); | |
| 1650 | const si = lmr.symbol(elf); | |
| 1631 | 1651 | const ni = ni: { |
| 1632 | 1652 | const sym = si.get(elf); |
| 1633 | 1653 | switch (sym.ni) { |
| ... | ... | @@ -1639,8 +1659,8 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo |
| 1639 | 1659 | }; |
| 1640 | 1660 | const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true }); |
| 1641 | 1661 | elf.nodes.appendAssumeCapacity(switch (lazy.kind) { |
| 1642 | .code => .{ .lazy_code = lazy.ty }, | |
| 1643 | .const_data => .{ .lazy_const_data = lazy.ty }, | |
| 1662 | .code => .{ .lazy_code = @enumFromInt(lmr.index) }, | |
| 1663 | .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) }, | |
| 1644 | 1664 | }); |
| 1645 | 1665 | sym.ni = ni; |
| 1646 | 1666 | switch (elf.symPtr(si)) { |
| ... | ... | @@ -1655,34 +1675,30 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo |
| 1655 | 1675 | break :ni sym.ni; |
| 1656 | 1676 | }; |
| 1657 | 1677 | |
| 1658 | const size = size: { | |
| 1659 | var required_alignment: InternPool.Alignment = .none; | |
| 1660 | var nw: MappedFile.Node.Writer = undefined; | |
| 1661 | ni.writer(&elf.mf, gpa, &nw); | |
| 1662 | defer nw.deinit(); | |
| 1663 | try codegen.generateLazySymbol( | |
| 1664 | &elf.base, | |
| 1665 | pt, | |
| 1666 | Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded, | |
| 1667 | lazy, | |
| 1668 | &required_alignment, | |
| 1669 | &nw.interface, | |
| 1670 | .none, | |
| 1671 | .{ .atom_index = @intFromEnum(si) }, | |
| 1672 | ); | |
| 1673 | break :size nw.interface.end; | |
| 1674 | }; | |
| 1675 | ||
| 1676 | const target_endian = elf.endian(); | |
| 1678 | var required_alignment: InternPool.Alignment = .none; | |
| 1679 | var nw: MappedFile.Node.Writer = undefined; | |
| 1680 | ni.writer(&elf.mf, gpa, &nw); | |
| 1681 | defer nw.deinit(); | |
| 1682 | try codegen.generateLazySymbol( | |
| 1683 | &elf.base, | |
| 1684 | pt, | |
| 1685 | Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded, | |
| 1686 | lazy, | |
| 1687 | &required_alignment, | |
| 1688 | &nw.interface, | |
| 1689 | .none, | |
| 1690 | .{ .atom_index = @intFromEnum(si) }, | |
| 1691 | ); | |
| 1692 | const target_endian = elf.targetEndian(); | |
| 1677 | 1693 | switch (elf.symPtr(si)) { |
| 1678 | 1694 | inline else => |sym| sym.size = |
| 1679 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), | |
| 1695 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(nw.interface.end), target_endian), | |
| 1680 | 1696 | } |
| 1681 | 1697 | si.applyLocationRelocs(elf); |
| 1682 | 1698 | } |
| 1683 | 1699 | |
| 1684 | 1700 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1685 | const target_endian = elf.endian(); | |
| 1701 | const target_endian = elf.targetEndian(); | |
| 1686 | 1702 | const file_offset = ni.fileLocation(&elf.mf, false).offset; |
| 1687 | 1703 | const node = elf.getNode(ni); |
| 1688 | 1704 | switch (node) { |
| ... | ... | @@ -1738,11 +1754,8 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1738 | 1754 | .nav, .uav, .lazy_code, .lazy_const_data => { |
| 1739 | 1755 | const si = switch (node) { |
| 1740 | 1756 | else => unreachable, |
| 1741 | .nav => |nav| elf.navs.get(nav), | |
| 1742 | .uav => |uav| elf.uavs.get(uav), | |
| 1743 | .lazy_code => |ty| elf.lazy.getPtr(.code).map.get(ty), | |
| 1744 | .lazy_const_data => |ty| elf.lazy.getPtr(.const_data).map.get(ty), | |
| 1745 | }.?; | |
| 1757 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf), | |
| 1758 | }; | |
| 1746 | 1759 | switch (elf.shdrSlice()) { |
| 1747 | 1760 | inline else => |shdr, class| { |
| 1748 | 1761 | const sym = @field(elf.symPtr(si), @tagName(class)); |
| ... | ... | @@ -1773,7 +1786,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1773 | 1786 | } |
| 1774 | 1787 | |
| 1775 | 1788 | fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1776 | const target_endian = elf.endian(); | |
| 1789 | const target_endian = elf.targetEndian(); | |
| 1777 | 1790 | _, const size = ni.location(&elf.mf).resolve(&elf.mf); |
| 1778 | 1791 | const node = elf.getNode(ni); |
| 1779 | 1792 | switch (node) { |
| ... | ... | @@ -1957,65 +1970,74 @@ pub fn printNode( |
| 1957 | 1970 | indent: usize, |
| 1958 | 1971 | ) !void { |
| 1959 | 1972 | const node = elf.getNode(ni); |
| 1960 | const mf_node = &elf.mf.nodes.items[@intFromEnum(ni)]; | |
| 1961 | const off, const size = mf_node.location().resolve(&elf.mf); | |
| 1962 | 1973 | try w.splatByteAll(' ', indent); |
| 1963 | 1974 | try w.writeAll(@tagName(node)); |
| 1964 | 1975 | switch (node) { |
| 1965 | 1976 | else => {}, |
| 1966 | 1977 | .section => |si| try w.print("({s})", .{elf.sectionName(si)}), |
| 1967 | .nav => |nav_index| { | |
| 1978 | .nav => |nmi| { | |
| 1968 | 1979 | const zcu = elf.base.comp.zcu.?; |
| 1969 | 1980 | const ip = &zcu.intern_pool; |
| 1970 | const nav = ip.getNav(nav_index); | |
| 1981 | const nav = ip.getNav(nmi.navIndex(elf)); | |
| 1971 | 1982 | try w.print("({f}, {f})", .{ |
| 1972 | 1983 | Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }), |
| 1973 | 1984 | nav.fqn.fmt(ip), |
| 1974 | 1985 | }); |
| 1975 | 1986 | }, |
| 1976 | .uav => |uav| { | |
| 1987 | .uav => |umi| { | |
| 1977 | 1988 | const zcu = elf.base.comp.zcu.?; |
| 1978 | const val: Value = .fromInterned(uav); | |
| 1989 | const val: Value = .fromInterned(umi.uavValue(elf)); | |
| 1979 | 1990 | try w.print("({f}, {f})", .{ |
| 1980 | 1991 | val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }), |
| 1981 | 1992 | val.fmtValue(.{ .zcu = zcu, .tid = tid }), |
| 1982 | 1993 | }); |
| 1983 | 1994 | }, |
| 1995 | inline .lazy_code, .lazy_const_data => |lmi| try w.print("({f})", .{ | |
| 1996 | Type.fromInterned(lmi.lazySymbol(elf).ty).fmt(.{ | |
| 1997 | .zcu = elf.base.comp.zcu.?, | |
| 1998 | .tid = tid, | |
| 1999 | }), | |
| 2000 | }), | |
| 1984 | 2001 | } |
| 1985 | try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{ | |
| 1986 | @intFromEnum(ni), | |
| 1987 | off, | |
| 1988 | size, | |
| 1989 | mf_node.flags.alignment.toByteUnits(), | |
| 1990 | if (mf_node.flags.fixed) " fixed" else "", | |
| 1991 | if (mf_node.flags.moved) " moved" else "", | |
| 1992 | if (mf_node.flags.resized) " resized" else "", | |
| 1993 | if (mf_node.flags.has_content) " has_content" else "", | |
| 1994 | }); | |
| 1995 | var child_ni = mf_node.first; | |
| 1996 | switch (child_ni) { | |
| 1997 | .none => { | |
| 1998 | const file_loc = ni.fileLocation(&elf.mf, false); | |
| 1999 | if (file_loc.size == 0) return; | |
| 2000 | var address = file_loc.offset; | |
| 2001 | const line_len = 0x10; | |
| 2002 | var line_it = std.mem.window( | |
| 2003 | u8, | |
| 2004 | elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], | |
| 2005 | line_len, | |
| 2006 | line_len, | |
| 2007 | ); | |
| 2008 | while (line_it.next()) |line_bytes| : (address += line_len) { | |
| 2009 | try w.splatByteAll(' ', indent + 1); | |
| 2010 | try w.print("{x:0>8}", .{address}); | |
| 2011 | for (line_bytes) |byte| try w.print(" {x:0>2}", .{byte}); | |
| 2012 | try w.writeByte('\n'); | |
| 2013 | } | |
| 2014 | }, | |
| 2015 | else => while (child_ni != .none) { | |
| 2016 | try elf.printNode(tid, w, child_ni, indent + 1); | |
| 2017 | child_ni = elf.mf.nodes.items[@intFromEnum(child_ni)].next; | |
| 2018 | }, | |
| 2002 | { | |
| 2003 | const mf_node = &elf.mf.nodes.items[@intFromEnum(ni)]; | |
| 2004 | const off, const size = mf_node.location().resolve(&elf.mf); | |
| 2005 | try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{ | |
| 2006 | @intFromEnum(ni), | |
| 2007 | off, | |
| 2008 | size, | |
| 2009 | mf_node.flags.alignment.toByteUnits(), | |
| 2010 | if (mf_node.flags.fixed) " fixed" else "", | |
| 2011 | if (mf_node.flags.moved) " moved" else "", | |
| 2012 | if (mf_node.flags.resized) " resized" else "", | |
| 2013 | if (mf_node.flags.has_content) " has_content" else "", | |
| 2014 | }); | |
| 2015 | } | |
| 2016 | var leaf = true; | |
| 2017 | var child_it = ni.children(&elf.mf); | |
| 2018 | while (child_it.next()) |child_ni| { | |
| 2019 | leaf = false; | |
| 2020 | try elf.printNode(tid, w, child_ni, indent + 1); | |
| 2021 | } | |
| 2022 | if (leaf) { | |
| 2023 | const file_loc = ni.fileLocation(&elf.mf, false); | |
| 2024 | if (file_loc.size == 0) return; | |
| 2025 | var address = file_loc.offset; | |
| 2026 | const line_len = 0x10; | |
| 2027 | var line_it = std.mem.window( | |
| 2028 | u8, | |
| 2029 | elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], | |
| 2030 | line_len, | |
| 2031 | line_len, | |
| 2032 | ); | |
| 2033 | while (line_it.next()) |line_bytes| : (address += line_len) { | |
| 2034 | try w.splatByteAll(' ', indent + 1); | |
| 2035 | try w.print("{x:0>8} ", .{address}); | |
| 2036 | for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte}); | |
| 2037 | try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1); | |
| 2038 | for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.'); | |
| 2039 | try w.writeByte('\n'); | |
| 2040 | } | |
| 2019 | 2041 | } |
| 2020 | 2042 | } |
| 2021 | 2043 |
src/link/MappedFile.zig+50-20| ... | ... | @@ -34,17 +34,28 @@ pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile { |
| 34 | 34 | .writers = .{}, |
| 35 | 35 | }; |
| 36 | 36 | errdefer mf.deinit(gpa); |
| 37 | const size: u64, const blksize = if (is_windows) | |
| 38 | .{ try windows.GetFileSizeEx(file.handle), 1 } | |
| 39 | else stat: { | |
| 37 | const size: u64, const block_size = stat: { | |
| 38 | if (is_windows) { | |
| 39 | var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined; | |
| 40 | break :stat .{ | |
| 41 | try windows.GetFileSizeEx(file.handle), | |
| 42 | switch (windows.ntdll.NtQuerySystemInformation( | |
| 43 | .SystemBasicInformation, | |
| 44 | &sbi, | |
| 45 | @sizeOf(windows.SYSTEM_BASIC_INFORMATION), | |
| 46 | null, | |
| 47 | )) { | |
| 48 | .SUCCESS => @max(sbi.PageSize, sbi.AllocationGranularity), | |
| 49 | else => std.heap.page_size_max, | |
| 50 | }, | |
| 51 | }; | |
| 52 | } | |
| 40 | 53 | const stat = try std.posix.fstat(mf.file.handle); |
| 41 | 54 | if (!std.posix.S.ISREG(stat.mode)) return error.PathAlreadyExists; |
| 42 | break :stat .{ @bitCast(stat.size), stat.blksize }; | |
| 55 | break :stat .{ @bitCast(stat.size), @max(std.heap.pageSize(), stat.blksize) }; | |
| 43 | 56 | }; |
| 44 | 57 | mf.flags = .{ |
| 45 | .block_size = .fromByteUnits( | |
| 46 | std.math.ceilPowerOfTwoAssert(usize, @max(std.heap.pageSize(), blksize)), | |
| 47 | ), | |
| 58 | .block_size = .fromByteUnits(std.math.ceilPowerOfTwoAssert(usize, block_size)), | |
| 48 | 59 | .copy_file_range_unsupported = false, |
| 49 | 60 | .fallocate_insert_range_unsupported = false, |
| 50 | 61 | .fallocate_punch_hole_unsupported = false, |
| ... | ... | @@ -90,9 +101,11 @@ pub const Node = extern struct { |
| 90 | 101 | resized: bool, |
| 91 | 102 | /// Whether this node might contain non-zero bytes. |
| 92 | 103 | has_content: bool, |
| 104 | /// Whether a moved event on this node bubbles down to children. | |
| 105 | bubbles_moved: bool, | |
| 93 | 106 | unused: @Type(.{ .int = .{ |
| 94 | 107 | .signedness = .unsigned, |
| 95 | .bits = 32 - @bitSizeOf(std.mem.Alignment) - 5, | |
| 108 | .bits = 32 - @bitSizeOf(std.mem.Alignment) - 6, | |
| 96 | 109 | } }) = 0, |
| 97 | 110 | }; |
| 98 | 111 | |
| ... | ... | @@ -136,6 +149,25 @@ pub const Node = extern struct { |
| 136 | 149 | return &mf.nodes.items[@intFromEnum(ni)]; |
| 137 | 150 | } |
| 138 | 151 | |
| 152 | pub fn parent(ni: Node.Index, mf: *const MappedFile) Node.Index { | |
| 153 | return ni.get(mf).parent; | |
| 154 | } | |
| 155 | ||
| 156 | pub const ChildIterator = struct { | |
| 157 | mf: *const MappedFile, | |
| 158 | ni: Node.Index, | |
| 159 | ||
| 160 | pub fn next(it: *ChildIterator) ?Node.Index { | |
| 161 | const ni = it.ni; | |
| 162 | if (ni == .none) return null; | |
| 163 | it.ni = ni.get(it.mf).next; | |
| 164 | return ni; | |
| 165 | } | |
| 166 | }; | |
| 167 | pub fn children(ni: Node.Index, mf: *const MappedFile) ChildIterator { | |
| 168 | return .{ .mf = mf, .ni = ni.get(mf).first }; | |
| 169 | } | |
| 170 | ||
| 139 | 171 | pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void { |
| 140 | 172 | var child_ni = ni.get(mf).last; |
| 141 | 173 | while (child_ni != .none) { |
| ... | ... | @@ -147,9 +179,10 @@ pub const Node = extern struct { |
| 147 | 179 | pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool { |
| 148 | 180 | var parent_ni = ni; |
| 149 | 181 | while (parent_ni != Node.Index.root) { |
| 150 | const parent = parent_ni.get(mf); | |
| 151 | if (parent.flags.moved) return true; | |
| 152 | parent_ni = parent.parent; | |
| 182 | const parent_node = parent_ni.get(mf); | |
| 183 | if (!parent_node.flags.bubbles_moved) break; | |
| 184 | if (parent_node.flags.moved) return true; | |
| 185 | parent_ni = parent_node.parent; | |
| 153 | 186 | } |
| 154 | 187 | return false; |
| 155 | 188 | } |
| ... | ... | @@ -163,12 +196,7 @@ pub const Node = extern struct { |
| 163 | 196 | return node_moved.*; |
| 164 | 197 | } |
| 165 | 198 | fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void { |
| 166 | var parent_ni = ni; | |
| 167 | while (parent_ni != Node.Index.root) { | |
| 168 | const parent_node = parent_ni.get(mf); | |
| 169 | if (parent_node.flags.moved) return; | |
| 170 | parent_ni = parent_node.parent; | |
| 171 | } | |
| 199 | if (ni.hasMoved(mf)) return; | |
| 172 | 200 | const node = ni.get(mf); |
| 173 | 201 | node.flags.moved = true; |
| 174 | 202 | if (node.flags.resized) return; |
| ... | ... | @@ -242,10 +270,10 @@ pub const Node = extern struct { |
| 242 | 270 | var offset, const size = ni.location(mf).resolve(mf); |
| 243 | 271 | var parent_ni = ni; |
| 244 | 272 | while (true) { |
| 245 | const parent = parent_ni.get(mf); | |
| 246 | if (set_has_content) parent.flags.has_content = true; | |
| 273 | const parent_node = parent_ni.get(mf); | |
| 274 | if (set_has_content) parent_node.flags.has_content = true; | |
| 247 | 275 | if (parent_ni == .none) break; |
| 248 | parent_ni = parent.parent; | |
| 276 | parent_ni = parent_node.parent; | |
| 249 | 277 | offset += parent_ni.location(mf).resolve(mf)[0]; |
| 250 | 278 | } |
| 251 | 279 | return .{ .offset = offset, .size = size }; |
| ... | ... | @@ -449,6 +477,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 449 | 477 | .moved = true, |
| 450 | 478 | .resized = true, |
| 451 | 479 | .has_content = false, |
| 480 | .bubbles_moved = opts.add_node.bubbles_moved, | |
| 452 | 481 | }, |
| 453 | 482 | .location_payload = location_payload, |
| 454 | 483 | }; |
| ... | ... | @@ -471,6 +500,7 @@ pub const AddNodeOptions = struct { |
| 471 | 500 | fixed: bool = false, |
| 472 | 501 | moved: bool = false, |
| 473 | 502 | resized: bool = false, |
| 503 | bubbles_moved: bool = true, | |
| 474 | 504 | }; |
| 475 | 505 | |
| 476 | 506 | pub fn addOnlyChildNode( |
src/target.zig+1-1| ... | ... | @@ -233,7 +233,7 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool { |
| 233 | 233 | |
| 234 | 234 | pub fn hasNewLinkerSupport(ofmt: std.Target.ObjectFormat, backend: std.builtin.CompilerBackend) bool { |
| 235 | 235 | return switch (ofmt) { |
| 236 | .elf => switch (backend) { | |
| 236 | .elf, .coff => switch (backend) { | |
| 237 | 237 | .stage2_x86_64 => true, |
| 238 | 238 | else => false, |
| 239 | 239 | }, |
test/behavior/cast.zig-2| ... | ... | @@ -1650,7 +1650,6 @@ test "coerce between pointers of compatible differently-named floats" { |
| 1650 | 1650 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest; |
| 1651 | 1651 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1652 | 1652 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1653 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 1654 | 1653 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1655 | 1654 | |
| 1656 | 1655 | if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { |
| ... | ... | @@ -2883,7 +2882,6 @@ test "@intFromFloat vector boundary cases" { |
| 2883 | 2882 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 2884 | 2883 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2885 | 2884 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 2886 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | |
| 2887 | 2885 | |
| 2888 | 2886 | const S = struct { |
| 2889 | 2887 | fn case(comptime I: type, unshifted_inputs: [2]f32, expected: [2]I) !void { |
test/behavior/export_keyword.zig-1| ... | ... | @@ -43,7 +43,6 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void { |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | test "export function alias" { |
| 46 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 47 | 46 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 48 | 47 | |
| 49 | 48 | _ = struct { |
test/behavior/extern.zig-2| ... | ... | @@ -16,7 +16,6 @@ export var a_mystery_symbol: i32 = 1234; |
| 16 | 16 | |
| 17 | 17 | test "function extern symbol" { |
| 18 | 18 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 19 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | |
| 20 | 19 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 21 | 20 | |
| 22 | 21 | const a = @extern(*const fn () callconv(.c) i32, .{ .name = "a_mystery_function" }); |
| ... | ... | @@ -29,7 +28,6 @@ export fn a_mystery_function() i32 { |
| 29 | 28 | |
| 30 | 29 | test "function extern symbol matches extern decl" { |
| 31 | 30 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 32 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | |
| 33 | 31 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 34 | 32 | |
| 35 | 33 | const S = struct { |
test/behavior/floatop.zig-17| ... | ... | @@ -158,7 +158,6 @@ test "cmp f80/c_longdouble" { |
| 158 | 158 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 159 | 159 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 160 | 160 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 161 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 162 | 161 | |
| 163 | 162 | try testCmp(f80); |
| 164 | 163 | try comptime testCmp(f80); |
| ... | ... | @@ -283,7 +282,6 @@ test "vector cmp f80/c_longdouble" { |
| 283 | 282 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 284 | 283 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 285 | 284 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 286 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 287 | 285 | |
| 288 | 286 | try testCmpVector(f80); |
| 289 | 287 | try comptime testCmpVector(f80); |
| ... | ... | @@ -396,7 +394,6 @@ test "@sqrt f80/f128/c_longdouble" { |
| 396 | 394 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 397 | 395 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 398 | 396 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 399 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 400 | 397 | |
| 401 | 398 | if (builtin.os.tag == .freebsd) { |
| 402 | 399 | // TODO https://github.com/ziglang/zig/issues/10875 |
| ... | ... | @@ -526,7 +523,6 @@ test "@sin f80/f128/c_longdouble" { |
| 526 | 523 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 527 | 524 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 528 | 525 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 529 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 530 | 526 | |
| 531 | 527 | try testSin(f80); |
| 532 | 528 | comptime try testSin(f80); |
| ... | ... | @@ -596,7 +592,6 @@ test "@cos f80/f128/c_longdouble" { |
| 596 | 592 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 597 | 593 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 598 | 594 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 599 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 600 | 595 | |
| 601 | 596 | try testCos(f80); |
| 602 | 597 | try comptime testCos(f80); |
| ... | ... | @@ -666,7 +661,6 @@ test "@tan f80/f128/c_longdouble" { |
| 666 | 661 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 667 | 662 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 668 | 663 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 669 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 670 | 664 | |
| 671 | 665 | try testTan(f80); |
| 672 | 666 | try comptime testTan(f80); |
| ... | ... | @@ -736,7 +730,6 @@ test "@exp f80/f128/c_longdouble" { |
| 736 | 730 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 737 | 731 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 738 | 732 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 739 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 740 | 733 | |
| 741 | 734 | try testExp(f80); |
| 742 | 735 | try comptime testExp(f80); |
| ... | ... | @@ -810,7 +803,6 @@ test "@exp2 f80/f128/c_longdouble" { |
| 810 | 803 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 811 | 804 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 812 | 805 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 813 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 814 | 806 | |
| 815 | 807 | try testExp2(f80); |
| 816 | 808 | try comptime testExp2(f80); |
| ... | ... | @@ -879,7 +871,6 @@ test "@log f80/f128/c_longdouble" { |
| 879 | 871 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 880 | 872 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 881 | 873 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 882 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 883 | 874 | |
| 884 | 875 | try testLog(f80); |
| 885 | 876 | try comptime testLog(f80); |
| ... | ... | @@ -946,7 +937,6 @@ test "@log2 f80/f128/c_longdouble" { |
| 946 | 937 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 947 | 938 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 948 | 939 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 949 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 950 | 940 | |
| 951 | 941 | try testLog2(f80); |
| 952 | 942 | try comptime testLog2(f80); |
| ... | ... | @@ -1019,7 +1009,6 @@ test "@log10 f80/f128/c_longdouble" { |
| 1019 | 1009 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1020 | 1010 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1021 | 1011 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1022 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 1023 | 1012 | |
| 1024 | 1013 | try testLog10(f80); |
| 1025 | 1014 | try comptime testLog10(f80); |
| ... | ... | @@ -1086,7 +1075,6 @@ test "@abs f80/f128/c_longdouble" { |
| 1086 | 1075 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1087 | 1076 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1088 | 1077 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1089 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 1090 | 1078 | |
| 1091 | 1079 | try testFabs(f80); |
| 1092 | 1080 | try comptime testFabs(f80); |
| ... | ... | @@ -1204,7 +1192,6 @@ test "@floor f80/f128/c_longdouble" { |
| 1204 | 1192 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1205 | 1193 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1206 | 1194 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1207 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | |
| 1208 | 1195 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1209 | 1196 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1210 | 1197 | |
| ... | ... | @@ -1295,7 +1282,6 @@ test "@ceil f80/f128/c_longdouble" { |
| 1295 | 1282 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1296 | 1283 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1297 | 1284 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1298 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | |
| 1299 | 1285 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1300 | 1286 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1301 | 1287 | |
| ... | ... | @@ -1388,7 +1374,6 @@ test "@trunc f80/f128/c_longdouble" { |
| 1388 | 1374 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1389 | 1375 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1390 | 1376 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1391 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 1392 | 1377 | |
| 1393 | 1378 | if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) { |
| 1394 | 1379 | // https://github.com/ziglang/zig/issues/12602 |
| ... | ... | @@ -1485,7 +1470,6 @@ test "neg f80/f128/c_longdouble" { |
| 1485 | 1470 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1486 | 1471 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 1487 | 1472 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1488 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 1489 | 1473 | |
| 1490 | 1474 | try testNeg(f80); |
| 1491 | 1475 | try comptime testNeg(f80); |
| ... | ... | @@ -1741,7 +1725,6 @@ test "comptime calls are only memoized when float arguments are bit-for-bit equa |
| 1741 | 1725 | test "result location forwarded through unary float builtins" { |
| 1742 | 1726 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1743 | 1727 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1744 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | |
| 1745 | 1728 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1746 | 1729 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1747 | 1730 |
test/behavior/import_c_keywords.zig-1| ... | ... | @@ -31,7 +31,6 @@ test "import c keywords" { |
| 31 | 31 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 32 | 32 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 33 | 33 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 34 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 35 | 34 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 36 | 35 | |
| 37 | 36 | try std.testing.expect(int == .c_keyword_variable); |
test/behavior/math.zig+6-4| ... | ... | @@ -1416,7 +1416,6 @@ test "remainder division" { |
| 1416 | 1416 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1417 | 1417 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1418 | 1418 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1419 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | |
| 1420 | 1419 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1421 | 1420 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1422 | 1421 | |
| ... | ... | @@ -1425,6 +1424,8 @@ test "remainder division" { |
| 1425 | 1424 | return error.SkipZigTest; |
| 1426 | 1425 | } |
| 1427 | 1426 | |
| 1427 | if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest; | |
| 1428 | ||
| 1428 | 1429 | try comptime remdiv(f16); |
| 1429 | 1430 | try comptime remdiv(f32); |
| 1430 | 1431 | try comptime remdiv(f64); |
| ... | ... | @@ -1496,9 +1497,10 @@ test "float modulo division using @mod" { |
| 1496 | 1497 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1497 | 1498 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1498 | 1499 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1499 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | |
| 1500 | 1500 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1501 | 1501 | |
| 1502 | if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest; | |
| 1503 | ||
| 1502 | 1504 | try comptime fmod(f16); |
| 1503 | 1505 | try comptime fmod(f32); |
| 1504 | 1506 | try comptime fmod(f64); |
| ... | ... | @@ -1686,7 +1688,6 @@ test "signed zeros are represented properly" { |
| 1686 | 1688 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1687 | 1689 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1688 | 1690 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1689 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 1690 | 1691 | |
| 1691 | 1692 | const S = struct { |
| 1692 | 1693 | fn doTheTest() !void { |
| ... | ... | @@ -1824,7 +1825,8 @@ test "float divide by zero" { |
| 1824 | 1825 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1825 | 1826 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1826 | 1827 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1827 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | |
| 1828 | ||
| 1829 | if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest; | |
| 1828 | 1830 | |
| 1829 | 1831 | const S = struct { |
| 1830 | 1832 | fn doTheTest(comptime F: type, zero: F, one: F) !void { |
test/behavior/multiple_externs_with_conflicting_types.zig-1| ... | ... | @@ -14,7 +14,6 @@ test "call extern function defined with conflicting type" { |
| 14 | 14 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 15 | 15 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 16 | 16 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 17 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest; | |
| 18 | 17 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 19 | 18 | |
| 20 | 19 | @import("conflicting_externs/a.zig").issue529(null); |
test/behavior/x86_64/binary.zig+2-1| ... | ... | @@ -5255,7 +5255,8 @@ inline fn mod(comptime Type: type, lhs: Type, rhs: Type) Type { |
| 5255 | 5255 | return @mod(lhs, rhs); |
| 5256 | 5256 | } |
| 5257 | 5257 | test mod { |
| 5258 | if (@import("builtin").object_format == .coff and @import("builtin").target.abi != .gnu) return error.SkipZigTest; | |
| 5258 | const builtin = @import("builtin"); | |
| 5259 | if (builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest; | |
| 5259 | 5260 | const test_mod = binary(mod, .{}); |
| 5260 | 5261 | try test_mod.testInts(); |
| 5261 | 5262 | try test_mod.testIntVectors(); |
test/incremental/add_decl+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | //#target=wasm32-wasi-selfhosted |
test/incremental/add_decl_namespaced+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | //#target=wasm32-wasi-selfhosted |
test/incremental/analysis_error_and_syntax_error+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/bad_import+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/change_embed_file+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/change_enum_tag_type+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/change_exports+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 |
test/incremental/change_fn_type+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #update=initial version |
test/incremental/change_generic_line_number+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=wasm32-wasi-selfhosted |
| 3 | 4 | #update=initial version |
| 4 | 5 | #file=main.zig |
test/incremental/change_line_number+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=wasm32-wasi-selfhosted |
| 3 | 4 | #update=initial version |
| 4 | 5 | #file=main.zig |
test/incremental/change_module+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/change_panic_handler+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #update=initial version |
test/incremental/change_panic_handler_explicit+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #update=initial version |
test/incremental/change_shift_op+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/change_struct_same_fields+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/change_zon_file+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | //#target=wasm32-wasi-selfhosted |
test/incremental/change_zon_file_no_result_type+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | //#target=wasm32-wasi-selfhosted |
test/incremental/compile_error_then_log+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/compile_log+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/delete_comptime_decls+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/dependency_on_type_of_inferred_global+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/fix_astgen_failure+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/function_becomes_inline+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #update=non-inline version |
test/incremental/hello+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/make_decl_pub+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/modify_inline_fn+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/move_src+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/no_change_preserves_tag_names+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | //#target=wasm32-wasi-selfhosted |
test/incremental/recursive_function_becomes_non_recursive+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/remove_enum_field+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/remove_invalid_union_backing_enum+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/temporary_parse_error+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/type_becomes_comptime_only+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |
test/incremental/unreferenced_error+1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-windows-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #target=wasm32-wasi-selfhosted |