authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-09-21 23:14:28-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-02 17:44:52-04:00
loge1f3fc6ce289502cde1e52fa946476ff8e3bcaac
tree42231ed7f2348c3c19b495bf8d4eac3acbfce21b
parentd5f09f56e0327685dfcaeb889efd9d6a26461886

Coff2: create a new linker from scratch


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,7 +1082,7 @@ pub fn toElfMachine(target: *const Target) std.elf.EM {
1082 };1082 };
1083}1083}
10841084
1085pub fn toCoffMachine(target: *const Target) std.coff.MachineType {1085pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
1086 return switch (target.cpu.arch) {1086 return switch (target.cpu.arch) {
1087 .arm => .ARM,1087 .arm => .ARM,
1088 .thumb => .ARMNT,1088 .thumb => .ARMNT,
...@@ -1092,7 +1092,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.MachineType {...@@ -1092,7 +1092,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.MachineType {
1092 .riscv32 => .RISCV32,1092 .riscv32 => .RISCV32,
1093 .riscv64 => .RISCV64,1093 .riscv64 => .RISCV64,
1094 .x86 => .I386,1094 .x86 => .I386,
1095 .x86_64 => .X64,1095 .x86_64 => .AMD64,
10961096
1097 .amdgcn,1097 .amdgcn,
1098 .arc,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,7 +50,7 @@ pub fn eqlString(a: []const u8, b: []const u8) bool {
50}50}
5151
52pub fn hashString(s: []const u8) u32 {52pub 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}
5555
56/// Deprecated in favor of `ArrayHashMapWithAllocator` (no code changes needed)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,70 +2,9 @@ const std = @import("std.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3const mem = std.mem;3const mem = std.mem;
44
5pub const CoffHeaderFlags = packed struct {5pub const Header = extern 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
66pub const CoffHeader = extern struct {
67 /// The number that identifies the type of target machine.6 /// The number that identifies the type of target machine.
68 machine: MachineType,7 machine: IMAGE.FILE.MACHINE,
698
70 /// The number of sections. This indicates the size of the section table, which immediately follows the headers.9 /// The number of sections. This indicates the size of the section table, which immediately follows the headers.
71 number_of_sections: u16,10 number_of_sections: u16,
...@@ -88,49 +27,110 @@ pub const CoffHeader = extern struct {...@@ -88,49 +27,110 @@ pub const CoffHeader = extern struct {
88 size_of_optional_header: u16,27 size_of_optional_header: u16,
8928
90 /// The flags that indicate the attributes of the file.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};
9393
94// OptionalHeader.magic values94// OptionalHeader.magic values
95// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx95// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
96pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;96pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC = @intFromEnum(OptionalHeader.Magic.PE32);
97pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;97pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC = @intFromEnum(OptionalHeader.Magic.@"PE32+");
9898
99pub const DllFlags = packed struct {99pub const DllFlags = packed struct(u16) {
100 _reserved_0: u5 = 0,100 _reserved_0: u5 = 0,
101101
102 /// Image can handle a high entropy 64-bit virtual address space.102 /// Image can handle a high entropy 64-bit virtual address space.
103 HIGH_ENTROPY_VA: u1 = 0,103 HIGH_ENTROPY_VA: bool = false,
104104
105 /// DLL can be relocated at load time.105 /// DLL can be relocated at load time.
106 DYNAMIC_BASE: u1 = 0,106 DYNAMIC_BASE: bool = false,
107107
108 /// Code Integrity checks are enforced.108 /// Code Integrity checks are enforced.
109 FORCE_INTEGRITY: u1 = 0,109 FORCE_INTEGRITY: bool = false,
110110
111 /// Image is NX compatible.111 /// Image is NX compatible.
112 NX_COMPAT: u1 = 0,112 NX_COMPAT: bool = false,
113113
114 /// Isolation aware, but do not isolate the image.114 /// Isolation aware, but do not isolate the image.
115 NO_ISOLATION: u1 = 0,115 NO_ISOLATION: bool = false,
116116
117 /// Does not use structured exception (SE) handling. No SE handler may be called in this image.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,
119119
120 /// Do not bind the image.120 /// Do not bind the image.
121 NO_BIND: u1 = 0,121 NO_BIND: bool = false,
122122
123 /// Image must execute in an AppContainer.123 /// Image must execute in an AppContainer.
124 APPCONTAINER: u1 = 0,124 APPCONTAINER: bool = false,
125125
126 /// A WDM driver.126 /// A WDM driver.
127 WDM_DRIVER: u1 = 0,127 WDM_DRIVER: bool = false,
128128
129 /// Image supports Control Flow Guard.129 /// Image supports Control Flow Guard.
130 GUARD_CF: u1 = 0,130 GUARD_CF: bool = false,
131131
132 /// Terminal Server aware.132 /// Terminal Server aware.
133 TERMINAL_SERVER_AWARE: u1 = 0,133 TERMINAL_SERVER_AWARE: bool = false,
134};134};
135135
136pub const Subsystem = enum(u16) {136pub const Subsystem = enum(u16) {
...@@ -180,7 +180,7 @@ pub const Subsystem = enum(u16) {...@@ -180,7 +180,7 @@ pub const Subsystem = enum(u16) {
180};180};
181181
182pub const OptionalHeader = extern struct {182pub const OptionalHeader = extern struct {
183 magic: u16,183 magic: OptionalHeader.Magic,
184 major_linker_version: u8,184 major_linker_version: u8,
185 minor_linker_version: u8,185 minor_linker_version: u8,
186 size_of_code: u32,186 size_of_code: u32,
...@@ -188,71 +188,63 @@ pub const OptionalHeader = extern struct {...@@ -188,71 +188,63 @@ pub const OptionalHeader = extern struct {
188 size_of_uninitialized_data: u32,188 size_of_uninitialized_data: u32,
189 address_of_entry_point: u32,189 address_of_entry_point: u32,
190 base_of_code: u32,190 base_of_code: u32,
191};
192191
193pub const OptionalHeaderPE32 = extern struct {192 pub const Magic = enum(u16) {
194 magic: u16,193 PE32 = 0x10b,
195 major_linker_version: u8,194 @"PE32+" = 0x20b,
196 minor_linker_version: u8,195 _,
197 size_of_code: u32,196 };
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};
225197
226pub const OptionalHeaderPE64 = extern struct {198 pub const PE32 = extern struct {
227 magic: u16,199 standard: OptionalHeader,
228 major_linker_version: u8,200 base_of_data: u32,
229 minor_linker_version: u8,201 image_base: u32,
230 size_of_code: u32,202 section_alignment: u32,
231 size_of_initialized_data: u32,203 file_alignment: u32,
232 size_of_uninitialized_data: u32,204 major_operating_system_version: u16,
233 address_of_entry_point: u32,205 minor_operating_system_version: u16,
234 base_of_code: u32,206 major_image_version: u16,
235 image_base: u64,207 minor_image_version: u16,
236 section_alignment: u32,208 major_subsystem_version: u16,
237 file_alignment: u32,209 minor_subsystem_version: u16,
238 major_operating_system_version: u16,210 win32_version_value: u32,
239 minor_operating_system_version: u16,211 size_of_image: u32,
240 major_image_version: u16,212 size_of_headers: u32,
241 minor_image_version: u16,213 checksum: u32,
242 major_subsystem_version: u16,214 subsystem: Subsystem,
243 minor_subsystem_version: u16,215 dll_flags: DllFlags,
244 win32_version_value: u32,216 size_of_stack_reserve: u32,
245 size_of_image: u32,217 size_of_stack_commit: u32,
246 size_of_headers: u32,218 size_of_heap_reserve: u32,
247 checksum: u32,219 size_of_heap_commit: u32,
248 subsystem: Subsystem,220 loader_flags: u32,
249 dll_flags: DllFlags,221 number_of_rva_and_sizes: u32,
250 size_of_stack_reserve: u64,222 };
251 size_of_stack_commit: u64,223
252 size_of_heap_reserve: u64,224 pub const @"PE32+" = extern struct {
253 size_of_heap_commit: u64,225 standard: OptionalHeader,
254 loader_flags: u32,226 image_base: u64,
255 number_of_rva_and_sizes: u32,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};
257249
258pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;250pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
...@@ -319,7 +311,7 @@ pub const BaseRelocationDirectoryEntry = extern struct {...@@ -319,7 +311,7 @@ pub const BaseRelocationDirectoryEntry = extern struct {
319 block_size: u32,311 block_size: u32,
320};312};
321313
322pub const BaseRelocation = packed struct {314pub const BaseRelocation = packed struct(u16) {
323 /// 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.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 /// This offset specifies where the base relocation is to be applied.316 /// This offset specifies where the base relocation is to be applied.
325 offset: u12,317 offset: u12,
...@@ -447,12 +439,12 @@ pub const ImportDirectoryEntry = extern struct {...@@ -447,12 +439,12 @@ pub const ImportDirectoryEntry = extern struct {
447};439};
448440
449pub const ImportLookupEntry32 = struct {441pub const ImportLookupEntry32 = struct {
450 pub const ByName = packed struct {442 pub const ByName = packed struct(u32) {
451 name_table_rva: u31,443 name_table_rva: u31,
452 flag: u1 = 0,444 flag: u1 = 0,
453 };445 };
454446
455 pub const ByOrdinal = packed struct {447 pub const ByOrdinal = packed struct(u32) {
456 ordinal_number: u16,448 ordinal_number: u16,
457 unused: u15 = 0,449 unused: u15 = 0,
458 flag: u1 = 1,450 flag: u1 = 1,
...@@ -472,13 +464,13 @@ pub const ImportLookupEntry32 = struct {...@@ -472,13 +464,13 @@ pub const ImportLookupEntry32 = struct {
472};464};
473465
474pub const ImportLookupEntry64 = struct {466pub const ImportLookupEntry64 = struct {
475 pub const ByName = packed struct {467 pub const ByName = packed struct(u64) {
476 name_table_rva: u31,468 name_table_rva: u31,
477 unused: u32 = 0,469 unused: u32 = 0,
478 flag: u1 = 0,470 flag: u1 = 0,
479 };471 };
480472
481 pub const ByOrdinal = packed struct {473 pub const ByOrdinal = packed struct(u64) {
482 ordinal_number: u16,474 ordinal_number: u16,
483 unused: u47 = 0,475 unused: u47 = 0,
484 flag: u1 = 1,476 flag: u1 = 1,
...@@ -519,7 +511,7 @@ pub const SectionHeader = extern struct {...@@ -519,7 +511,7 @@ pub const SectionHeader = extern struct {
519 pointer_to_linenumbers: u32,511 pointer_to_linenumbers: u32,
520 number_of_relocations: u16,512 number_of_relocations: u16,
521 number_of_linenumbers: u16,513 number_of_linenumbers: u16,
522 flags: SectionHeaderFlags,514 flags: SectionHeader.Flags,
523515
524 pub fn getName(self: *align(1) const SectionHeader) ?[]const u8 {516 pub fn getName(self: *align(1) const SectionHeader) ?[]const u8 {
525 if (self.name[0] == '/') return null;517 if (self.name[0] == '/') return null;
...@@ -546,109 +538,121 @@ pub const SectionHeader = extern struct {...@@ -546,109 +538,121 @@ pub const SectionHeader = extern struct {
546 }538 }
547539
548 pub fn isCode(self: SectionHeader) bool {540 pub fn isCode(self: SectionHeader) bool {
549 return self.flags.CNT_CODE == 0b1;541 return self.flags.CNT_CODE;
550 }542 }
551543
552 pub fn isComdat(self: SectionHeader) bool {544 pub fn isComdat(self: SectionHeader) bool {
553 return self.flags.LNK_COMDAT == 0b1;545 return self.flags.LNK_COMDAT;
554 }546 }
555};
556547
557pub const SectionHeaderFlags = packed struct {548 pub const Flags = packed struct(u32) {
558 _reserved_0: u3 = 0,549 SCALE_INDEX: bool = false,
550
551 unused1: u2 = 0,
559552
560 /// The section should not be padded to the next boundary.553 /// The section should not be padded to the next boundary.
561 /// This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES.554 /// This flag is obsolete and is replaced by `.ALIGN = .@"1BYTES"`.
562 /// This is valid only for object files.555 /// This is valid only for object files.
563 TYPE_NO_PAD: u1 = 0,556 TYPE_NO_PAD: bool = false,
564557
565 _reserved_1: u1 = 0,558 unused4: u1 = 0,
566559
567 /// The section contains executable code.560 /// The section contains executable code.
568 CNT_CODE: u1 = 0,561 CNT_CODE: bool = false,
569562
570 /// The section contains initialized data.563 /// The section contains initialized data.
571 CNT_INITIALIZED_DATA: u1 = 0,564 CNT_INITIALIZED_DATA: bool = false,
572565
573 /// The section contains uninitialized data.566 /// The section contains uninitialized data.
574 CNT_UNINITIALIZED_DATA: u1 = 0,567 CNT_UNINITIALIZED_DATA: bool = false,
575568
576 /// Reserved for future use.569 /// Reserved for future use.
577 LNK_OTHER: u1 = 0,570 LNK_OTHER: bool = false,
578571
579 /// The section contains comments or other information.572 /// The section contains comments or other information.
580 /// The .drectve section has this type.573 /// The .drectve section has this type.
581 /// This is valid for object files only.574 /// This is valid for object files only.
582 LNK_INFO: u1 = 0,575 LNK_INFO: bool = false,
583576
584 _reserved_2: u1 = 0,577 unused10: u1 = 0,
585578
586 /// The section will not become part of the image.579 /// The section will not become part of the image.
587 /// This is valid only for object files.580 /// This is valid only for object files.
588 LNK_REMOVE: u1 = 0,581 LNK_REMOVE: bool = false,
589582
590 /// The section contains COMDAT data.583 /// The section contains COMDAT data.
591 /// For more information, see COMDAT Sections (Object Only).584 /// For more information, see COMDAT Sections (Object Only).
592 /// This is valid only for object files.585 /// This is valid only for object files.
593 LNK_COMDAT: u1 = 0,586 LNK_COMDAT: bool = false,
594587
595 _reserved_3: u2 = 0,588 unused13: u2 = 0,
596589
597 /// The section contains data referenced through the global pointer (GP).590 union14: packed union {
598 GPREL: u1 = 0,591 mask: u1,
592 /// The section contains data referenced through the global pointer (GP).
593 GPREL: bool,
594 MEM_FARDATA: bool,
595 } = .{ .mask = 0 },
599596
600 /// Reserved for future use.597 unused15: u1 = 0,
601 MEM_PURGEABLE: u1 = 0,
602598
603 /// Reserved for future use.599 union16: packed union {
604 MEM_16BIT: u1 = 0,600 mask: u1,
601 MEM_PURGEABLE: bool,
602 MEM_16BIT: bool,
603 } = .{ .mask = 0 },
605604
606 /// Reserved for future use.605 /// Reserved for future use.
607 MEM_LOCKED: u1 = 0,606 MEM_LOCKED: bool = false,
608607
609 /// Reserved for future use.608 /// Reserved for future use.
610 MEM_PRELOAD: u1 = 0,609 MEM_PRELOAD: bool = false,
611610
612 /// Takes on multiple values according to flags:611 ALIGN: SectionHeader.Flags.Align = .NONE,
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,
628612
629 /// The section contains extended relocations.613 /// The section contains extended relocations.
630 LNK_NRELOC_OVFL: u1 = 0,614 LNK_NRELOC_OVFL: bool = false,
631615
632 /// The section can be discarded as needed.616 /// The section can be discarded as needed.
633 MEM_DISCARDABLE: u1 = 0,617 MEM_DISCARDABLE: bool = false,
634618
635 /// The section cannot be cached.619 /// The section cannot be cached.
636 MEM_NOT_CACHED: u1 = 0,620 MEM_NOT_CACHED: bool = false,
637621
638 /// The section is not pageable.622 /// The section is not pageable.
639 MEM_NOT_PAGED: u1 = 0,623 MEM_NOT_PAGED: bool = false,
640624
641 /// The section can be shared in memory.625 /// The section can be shared in memory.
642 MEM_SHARED: u1 = 0,626 MEM_SHARED: bool = false,
643627
644 /// The section can be executed as code.628 /// The section can be executed as code.
645 MEM_EXECUTE: u1 = 0,629 MEM_EXECUTE: bool = false,
646630
647 /// The section can be read.631 /// The section can be read.
648 MEM_READ: u1 = 0,632 MEM_READ: bool = false,
649633
650 /// The section can be written to.634 /// The section can be written to.
651 MEM_WRITE: u1 = 0,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};
653657
654pub const Symbol = struct {658pub const Symbol = struct {
...@@ -691,7 +695,7 @@ pub const SectionNumber = enum(u16) {...@@ -691,7 +695,7 @@ pub const SectionNumber = enum(u16) {
691 _,695 _,
692};696};
693697
694pub const SymType = packed struct {698pub const SymType = packed struct(u16) {
695 complex_type: ComplexType,699 complex_type: ComplexType,
696 base_type: BaseType,700 base_type: BaseType,
697};701};
...@@ -982,87 +986,7 @@ pub const DebugInfoDefinition = struct {...@@ -982,87 +986,7 @@ pub const DebugInfoDefinition = struct {
982 unused_3: [2]u8,986 unused_3: [2]u8,
983};987};
984988
985pub const MachineType = enum(u16) {989pub const Error = error{
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
1065pub const CoffError = error{
1066 InvalidPEMagic,990 InvalidPEMagic,
1067 InvalidPEHeader,991 InvalidPEHeader,
1068 InvalidMachine,992 InvalidMachine,
...@@ -1104,7 +1028,7 @@ pub const Coff = struct {...@@ -1104,7 +1028,7 @@ pub const Coff = struct {
11041028
1105 // Do some basic validation upfront1029 // Do some basic validation upfront
1106 if (is_image) {1030 if (is_image) {
1107 const coff_header = coff.getCoffHeader();1031 const coff_header = coff.getHeader();
1108 if (coff_header.size_of_optional_header == 0) return error.MissingPEHeader;1032 if (coff_header.size_of_optional_header == 0) return error.MissingPEHeader;
1109 }1033 }
11101034
...@@ -1161,31 +1085,31 @@ pub const Coff = struct {...@@ -1161,31 +1085,31 @@ pub const Coff = struct {
1161 return self.data[start .. start + len];1085 return self.data[start .. start + len];
1162 }1086 }
11631087
1164 pub fn getCoffHeader(self: Coff) CoffHeader {1088 pub fn getHeader(self: Coff) Header {
1165 return @as(*align(1) const CoffHeader, @ptrCast(self.data[self.coff_header_offset..][0..@sizeOf(CoffHeader)])).*;1089 return @as(*align(1) const Header, @ptrCast(self.data[self.coff_header_offset..][0..@sizeOf(Header)])).*;
1166 }1090 }
11671091
1168 pub fn getOptionalHeader(self: Coff) OptionalHeader {1092 pub fn getOptionalHeader(self: Coff) OptionalHeader {
1169 assert(self.is_image);1093 assert(self.is_image);
1170 const offset = self.coff_header_offset + @sizeOf(CoffHeader);1094 const offset = self.coff_header_offset + @sizeOf(Header);
1171 return @as(*align(1) const OptionalHeader, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader)])).*;1095 return @as(*align(1) const OptionalHeader, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader)])).*;
1172 }1096 }
11731097
1174 pub fn getOptionalHeader32(self: Coff) OptionalHeaderPE32 {1098 pub fn getOptionalHeader32(self: Coff) OptionalHeader.PE32 {
1175 assert(self.is_image);1099 assert(self.is_image);
1176 const offset = self.coff_header_offset + @sizeOf(CoffHeader);1100 const offset = self.coff_header_offset + @sizeOf(Header);
1177 return @as(*align(1) const OptionalHeaderPE32, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeaderPE32)])).*;1101 return @as(*align(1) const OptionalHeader.PE32, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader.PE32)])).*;
1178 }1102 }
11791103
1180 pub fn getOptionalHeader64(self: Coff) OptionalHeaderPE64 {1104 pub fn getOptionalHeader64(self: Coff) OptionalHeader.@"PE32+" {
1181 assert(self.is_image);1105 assert(self.is_image);
1182 const offset = self.coff_header_offset + @sizeOf(CoffHeader);1106 const offset = self.coff_header_offset + @sizeOf(Header);
1183 return @as(*align(1) const OptionalHeaderPE64, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeaderPE64)])).*;1107 return @as(*align(1) const OptionalHeader.@"PE32+", @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader.@"PE32+")])).*;
1184 }1108 }
11851109
1186 pub fn getImageBase(self: Coff) u64 {1110 pub fn getImageBase(self: Coff) u64 {
1187 const hdr = self.getOptionalHeader();1111 const hdr = self.getOptionalHeader();
1188 return switch (hdr.magic) {1112 return switch (@intFromEnum(hdr.magic)) {
1189 IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().image_base,1113 IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().image_base,
1190 IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().image_base,1114 IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().image_base,
1191 else => unreachable, // We assume we have validated the header already1115 else => unreachable, // We assume we have validated the header already
...@@ -1194,7 +1118,7 @@ pub const Coff = struct {...@@ -1194,7 +1118,7 @@ pub const Coff = struct {
11941118
1195 pub fn getNumberOfDataDirectories(self: Coff) u32 {1119 pub fn getNumberOfDataDirectories(self: Coff) u32 {
1196 const hdr = self.getOptionalHeader();1120 const hdr = self.getOptionalHeader();
1197 return switch (hdr.magic) {1121 return switch (@intFromEnum(hdr.magic)) {
1198 IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().number_of_rva_and_sizes,1122 IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().number_of_rva_and_sizes,
1199 IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().number_of_rva_and_sizes,1123 IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().number_of_rva_and_sizes,
1200 else => unreachable, // We assume we have validated the header already1124 else => unreachable, // We assume we have validated the header already
...@@ -1203,17 +1127,17 @@ pub const Coff = struct {...@@ -1203,17 +1127,17 @@ pub const Coff = struct {
12031127
1204 pub fn getDataDirectories(self: *const Coff) []align(1) const ImageDataDirectory {1128 pub fn getDataDirectories(self: *const Coff) []align(1) const ImageDataDirectory {
1205 const hdr = self.getOptionalHeader();1129 const hdr = self.getOptionalHeader();
1206 const size: usize = switch (hdr.magic) {1130 const size: usize = switch (@intFromEnum(hdr.magic)) {
1207 IMAGE_NT_OPTIONAL_HDR32_MAGIC => @sizeOf(OptionalHeaderPE32),1131 IMAGE_NT_OPTIONAL_HDR32_MAGIC => @sizeOf(OptionalHeader.PE32),
1208 IMAGE_NT_OPTIONAL_HDR64_MAGIC => @sizeOf(OptionalHeaderPE64),1132 IMAGE_NT_OPTIONAL_HDR64_MAGIC => @sizeOf(OptionalHeader.@"PE32+"),
1209 else => unreachable, // We assume we have validated the header already1133 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 return @as([*]align(1) const ImageDataDirectory, @ptrCast(self.data[offset..]))[0..self.getNumberOfDataDirectories()];1136 return @as([*]align(1) const ImageDataDirectory, @ptrCast(self.data[offset..]))[0..self.getNumberOfDataDirectories()];
1213 }1137 }
12141138
1215 pub fn getSymtab(self: *const Coff) ?Symtab {1139 pub fn getSymtab(self: *const Coff) ?Symtab {
1216 const coff_header = self.getCoffHeader();1140 const coff_header = self.getHeader();
1217 if (coff_header.pointer_to_symbol_table == 0) return null;1141 if (coff_header.pointer_to_symbol_table == 0) return null;
12181142
1219 const offset = coff_header.pointer_to_symbol_table;1143 const offset = coff_header.pointer_to_symbol_table;
...@@ -1222,7 +1146,7 @@ pub const Coff = struct {...@@ -1222,7 +1146,7 @@ pub const Coff = struct {
1222 }1146 }
12231147
1224 pub fn getStrtab(self: *const Coff) error{InvalidStrtabSize}!?Strtab {1148 pub fn getStrtab(self: *const Coff) error{InvalidStrtabSize}!?Strtab {
1225 const coff_header = self.getCoffHeader();1149 const coff_header = self.getHeader();
1226 if (coff_header.pointer_to_symbol_table == 0) return null;1150 if (coff_header.pointer_to_symbol_table == 0) return null;
12271151
1228 const offset = coff_header.pointer_to_symbol_table + Symbol.sizeOf() * coff_header.number_of_symbols;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,8 +1162,8 @@ pub const Coff = struct {
1238 }1162 }
12391163
1240 pub fn getSectionHeaders(self: *const Coff) []align(1) const SectionHeader {1164 pub fn getSectionHeaders(self: *const Coff) []align(1) const SectionHeader {
1241 const coff_header = self.getCoffHeader();1165 const coff_header = self.getHeader();
1242 const offset = self.coff_header_offset + @sizeOf(CoffHeader) + coff_header.size_of_optional_header;1166 const offset = self.coff_header_offset + @sizeOf(Header) + coff_header.size_of_optional_header;
1243 return @as([*]align(1) const SectionHeader, @ptrCast(self.data.ptr + offset))[0..coff_header.number_of_sections];1167 return @as([*]align(1) const SectionHeader, @ptrCast(self.data.ptr + offset))[0..coff_header.number_of_sections];
1244 }1168 }
12451169
...@@ -1414,14 +1338,14 @@ pub const Strtab = struct {...@@ -1414,14 +1338,14 @@ pub const Strtab = struct {
1414};1338};
14151339
1416pub const ImportHeader = extern struct {1340pub const ImportHeader = extern struct {
1417 sig1: MachineType,1341 sig1: IMAGE.FILE.MACHINE,
1418 sig2: u16,1342 sig2: u16,
1419 version: u16,1343 version: u16,
1420 machine: MachineType,1344 machine: IMAGE.FILE.MACHINE,
1421 time_date_stamp: u32,1345 time_date_stamp: u32,
1422 size_of_data: u32,1346 size_of_data: u32,
1423 hint: u16,1347 hint: u16,
1424 types: packed struct {1348 types: packed struct(u32) {
1425 type: ImportType,1349 type: ImportType,
1426 name_type: ImportNameType,1350 name_type: ImportNameType,
1427 reserved: u11,1351 reserved: u11,
...@@ -1461,119 +1385,534 @@ pub const Relocation = extern struct {...@@ -1461,119 +1385,534 @@ pub const Relocation = extern struct {
1461 type: u16,1385 type: u16,
1462};1386};
14631387
1464pub const ImageRelAmd64 = enum(u16) {1388pub const IMAGE = struct {
1465 /// The relocation is ignored.1389 pub const FILE = struct {
1466 absolute = 0,1390 /// Machine Types
14671391 /// The Machine field has one of the following values, which specify the CPU type.
1468 /// The 64-bit VA of the relocation target.1392 /// An image file can be run only on the specified machine or on a system that emulates the specified machine.
1469 addr64 = 1,1393 pub const MACHINE = enum(u16) {
14701394 /// The content of this field is assumed to be applicable to any machine type
1471 /// The 32-bit VA of the relocation target.1395 UNKNOWN = 0x0,
1472 addr32 = 2,1396 /// Alpha AXP, 32-bit address space
14731397 ALPHA = 0x184,
1474 /// The 32-bit address without an image base.1398 /// Alpha 64, 64-bit address space
1475 addr32nb = 3,1399 ALPHA64 = 0x284,
14761400 /// Matsushita AM33
1477 /// The 32-bit relative address from the byte following the relocation.1401 AM33 = 0x1d3,
1478 rel32 = 4,1402 /// x64
14791403 AMD64 = 0x8664,
1480 /// The 32-bit address relative to byte distance 1 from the relocation.1404 /// ARM little endian
1481 rel32_1 = 5,1405 ARM = 0x1c0,
14821406 /// ARM64 little endian
1483 /// The 32-bit address relative to byte distance 2 from the relocation.1407 ARM64 = 0xaa64,
1484 rel32_2 = 6,1408 /// ABI that enables interoperability between native ARM64 and emulated x64 code.
14851409 ARM64EC = 0xA641,
1486 /// The 32-bit address relative to byte distance 3 from the relocation.1410 /// Binary format that allows both native ARM64 and ARM64EC code to coexist in the same file.
1487 rel32_3 = 7,1411 ARM64X = 0xA64E,
14881412 /// ARM Thumb-2 little endian
1489 /// The 32-bit address relative to byte distance 4 from the relocation.1413 ARMNT = 0x1c4,
1490 rel32_4 = 8,1414 /// EFI byte code
14911415 EBC = 0xebc,
1492 /// The 32-bit address relative to byte distance 5 from the relocation.1416 /// Intel 386 or later processors and compatible processors
1493 rel32_5 = 9,1417 I386 = 0x14c,
14941418 /// Intel Itanium processor family
1495 /// The 16-bit section index of the section that contains the target.1419 IA64 = 0x200,
1496 /// This is used to support debugging information.1420 /// LoongArch 32-bit processor family
1497 section = 10,1421 LOONGARCH32 = 0x6232,
14981422 /// LoongArch 64-bit processor family
1499 /// The 32-bit offset of the target from the beginning of its section.1423 LOONGARCH64 = 0x6264,
1500 /// This is used to support debugging information and static thread local storage.1424 /// Mitsubishi M32R little endian
1501 secrel = 11,1425 M32R = 0x9041,
15021426 /// MIPS16
1503 /// A 7-bit unsigned offset from the base of the section that contains the target.1427 MIPS16 = 0x266,
1504 secrel7 = 12,1428 /// MIPS with FPU
15051429 MIPSFPU = 0x366,
1506 /// CLR tokens.1430 /// MIPS16 with FPU
1507 token = 13,1431 MIPSFPU16 = 0x466,
15081432 /// Power PC little endian
1509 /// A 32-bit signed span-dependent value emitted into the object.1433 POWERPC = 0x1f0,
1510 srel32 = 14,1434 /// Power PC with floating point support
15111435 POWERPCFP = 0x1f1,
1512 /// A pair that must immediately follow every span-dependent value.1436 /// MIPS I compatible 32-bit big endian
1513 pair = 15,1437 R3000BE = 0x160,
15141438 /// MIPS I compatible 32-bit little endian
1515 /// A 32-bit signed span-dependent value that is applied at link time.1439 R3000 = 0x162,
1516 sspan32 = 16,1440 /// MIPS III compatible 64-bit little endian
15171441 R4000 = 0x166,
1518 _,1442 /// MIPS IV compatible 64-bit little endian
1519};1443 R10000 = 0x168,
15201444 /// RISC-V 32-bit address space
1521pub const ImageRelArm64 = enum(u16) {1445 RISCV32 = 0x5032,
1522 /// The relocation is ignored.1446 /// RISC-V 64-bit address space
1523 absolute = 0,1447 RISCV64 = 0x5064,
15241448 /// RISC-V 128-bit address space
1525 /// The 32-bit VA of the target.1449 RISCV128 = 0x5128,
1526 addr32 = 1,1450 /// Hitachi SH3
15271451 SH3 = 0x1a2,
1528 /// The 32-bit RVA of the target.1452 /// Hitachi SH3 DSP
1529 addr32nb = 2,1453 SH3DSP = 0x1a3,
15301454 /// Hitachi SH4
1531 /// The 26-bit relative displacement to the target, for B and BL instructions.1455 SH4 = 0x1a6,
1532 branch26 = 3,1456 /// Hitachi SH5
15331457 SH5 = 0x1a8,
1534 /// The page base of the target, for ADRP instruction.1458 /// Thumb
1535 pagebase_rel21 = 4,1459 THUMB = 0x1c2,
15361460 /// MIPS little-endian WCE v2
1537 /// The 21-bit relative displacement to the target, for instruction ADR.1461 WCEMIPSV2 = 0x169,
1538 rel21 = 5,1462 _,
15391463 /// AXP 64 (Same as Alpha 64)
1540 /// The 12-bit page offset of the target, for instructions ADD/ADDS (immediate) with zero shift.1464 pub const AXP64: IMAGE.FILE.MACHINE = .ALPHA64;
1541 pageoffset_12a = 6,1465 };
15421466 };
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,
15521467
1553 /// Bit 12:23 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift.1468 pub const REL = struct {
1554 high12a = 10,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 };
15551510
1556 /// Bit 0:11 of section offset of the target, for instruction LDR (indexed, unsigned immediate).1511 /// ARM Processors
1557 low12l = 11,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 };
15581556
1559 /// CLR token.1557 /// ARM64 Processors
1560 token = 12,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 };
15611600
1562 /// The 16-bit section index of the section that contains the target.1601 /// Hitachi SuperH Processors
1563 /// This is used to support debugging information.1602 /// The following relocation type indicators are defined for SH3 and SH4 processors.
1564 section = 13,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 };
15651663
1566 /// The 64-bit VA of the relocation target.1664 /// IBM PowerPC Processors
1567 addr64 = 14,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 };
15681713
1569 /// The 19-bit offset to the relocation target, for conditional B instruction.1714 /// Intel 386 Processors
1570 branch19 = 15,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 };
15711744
1572 /// The 14-bit offset to the relocation target, for instructions TBZ and TBNZ.1745 /// Intel Itanium Processor Family (IPF)
1573 branch14 = 16,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 };
15741831
1575 /// The 32-bit relative address from the byte following the relocation.1832 /// MIPS Processors
1576 rel32 = 17,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 };
15771876
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,13 +78,15 @@ pub fn defaultQueryPageSize() usize {
78 };78 };
79 var size = global.cached_result.load(.unordered);79 var size = global.cached_result.load(.unordered);
80 if (size > 0) return size;80 if (size > 0) return size;
81 size = switch (builtin.os.tag) {81 size = 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),82 .linux => if (builtin.link_libc)
83 .driverkit, .ios, .macos, .tvos, .visionos, .watchos => blk: {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 const task_port = std.c.mach_task_self();87 const task_port = std.c.mach_task_self();
85 // mach_task_self may fail "if there are any resource failures or other errors".88 // mach_task_self may fail "if there are any resource failures or other errors".
86 if (task_port == std.c.TASK.NULL)89 if (task_port == std.c.TASK.NULL) break :size 0;
87 break :blk 0;
88 var info_count = std.c.TASK.VM.INFO_COUNT;90 var info_count = std.c.TASK.VM.INFO_COUNT;
89 var vm_info: std.c.task_vm_info_data_t = undefined;91 var vm_info: std.c.task_vm_info_data_t = undefined;
90 vm_info.page_size = 0;92 vm_info.page_size = 0;
...@@ -94,21 +96,28 @@ pub fn defaultQueryPageSize() usize {...@@ -94,21 +96,28 @@ pub fn defaultQueryPageSize() usize {
94 @as(std.c.task_info_t, @ptrCast(&vm_info)),96 @as(std.c.task_info_t, @ptrCast(&vm_info)),
95 &info_count,97 &info_count,
96 );98 );
97 assert(vm_info.page_size != 0);99 break :size @intCast(vm_info.page_size);
98 break :blk @intCast(vm_info.page_size);
99 },100 },
100 .windows => blk: {101 .windows => {
101 var info: std.os.windows.SYSTEM_INFO = undefined;102 var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined;
102 std.os.windows.kernel32.GetSystemInfo(&info);103 switch (windows.ntdll.NtQuerySystemInformation(
103 break :blk info.dwPageSize;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 else => if (builtin.link_libc)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 else if (builtin.os.tag == .freestanding or builtin.os.tag == .other)115 else if (builtin.os.tag == .freestanding or builtin.os.tag == .other)
108 @compileError("unsupported target: freestanding/other")116 @compileError("unsupported target: freestanding/other")
109 else117 else
110 @compileError("pageSize on " ++ @tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " is not supported without linking libc, using the default implementation"),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;
112121
113 assert(size >= page_size_min);122 assert(size >= page_size_min);
114 assert(size <= page_size_max);123 assert(size <= page_size_max);
src/Compilation.zig+17-9
...@@ -256,8 +256,8 @@ test_filters: []const []const u8,...@@ -256,8 +256,8 @@ test_filters: []const []const u8,
256256
257link_task_wait_group: WaitGroup = .{},257link_task_wait_group: WaitGroup = .{},
258link_prog_node: std.Progress.Node = .none,258link_prog_node: std.Progress.Node = .none,
259link_uav_prog_node: std.Progress.Node = .none,259link_const_prog_node: std.Progress.Node = .none,
260link_lazy_prog_node: std.Progress.Node = .none,260link_synth_prog_node: std.Progress.Node = .none,
261261
262llvm_opt_bisect_limit: c_int,262llvm_opt_bisect_limit: c_int,
263263
...@@ -1982,13 +1982,13 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options...@@ -1982,13 +1982,13 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
1982 };1982 };
1983 if (have_zcu and (!need_llvm or use_llvm)) {1983 if (have_zcu and (!need_llvm or use_llvm)) {
1984 if (output_mode == .Obj) break :s .zcu;1984 if (output_mode == .Obj) break :s .zcu;
1985 if (options.config.use_new_linker) break :s .zcu;
1986 switch (target_util.zigBackend(target, use_llvm)) {1985 switch (target_util.zigBackend(target, use_llvm)) {
1987 else => {},1986 else => {},
1988 .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) {1987 .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) {
1989 break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;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 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm1993 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm
1994 if (is_exe_or_dyn_lib) break :s .lib;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,22 +3081,30 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
3081 comp.link_prog_node = main_progress_node.start("Linking", 0);3081 comp.link_prog_node = main_progress_node.start("Linking", 0);
3082 if (lf.cast(.elf2)) |elf| {3082 if (lf.cast(.elf2)) |elf| {
3083 comp.link_prog_node.increaseEstimatedTotalItems(3);3083 comp.link_prog_node.increaseEstimatedTotalItems(3);
3084 comp.link_uav_prog_node = comp.link_prog_node.start("Constants", 0);3084 comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0);
3085 comp.link_lazy_prog_node = comp.link_prog_node.start("Synthetics", 0);3085 comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0);
3086 elf.mf.update_prog_node = comp.link_prog_node.start("Relocations", elf.mf.updates.items.len);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 defer {3094 defer {
3090 comp.link_prog_node.end();3095 comp.link_prog_node.end();
3091 comp.link_prog_node = .none;3096 comp.link_prog_node = .none;
3092 comp.link_uav_prog_node.end();3097 comp.link_const_prog_node.end();
3093 comp.link_uav_prog_node = .none;3098 comp.link_const_prog_node = .none;
3094 comp.link_lazy_prog_node.end();3099 comp.link_synth_prog_node.end();
3095 comp.link_lazy_prog_node = .none;3100 comp.link_synth_prog_node = .none;
3096 if (comp.bin_file) |lf| {3101 if (comp.bin_file) |lf| {
3097 if (lf.cast(.elf2)) |elf| {3102 if (lf.cast(.elf2)) |elf| {
3098 elf.mf.update_prog_node.end();3103 elf.mf.update_prog_node.end();
3099 elf.mf.update_prog_node = .none;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,6 +438,8 @@ pub fn resolve(options: Options) ResolveError!Config {
438438
439 if (options.use_new_linker) |x| break :b x;439 if (options.use_new_linker) |x| break :b x;
440440
441 if (target.ofmt == .coff) break :b true;
442
441 break :b options.incremental;443 break :b options.incremental;
442 };444 };
443445
src/InternPool.zig+3-3
...@@ -11919,10 +11919,10 @@ pub fn getString(ip: *InternPool, key: []const u8) OptionalNullTerminatedString...@@ -11919,10 +11919,10 @@ pub fn getString(ip: *InternPool, key: []const u8) OptionalNullTerminatedString
11919 var map_index = hash;11919 var map_index = hash;
11920 while (true) : (map_index += 1) {11920 while (true) : (map_index += 1) {
11921 map_index &= map_mask;11921 map_index &= map_mask;
11922 const entry = map.at(map_index);11922 const entry = &map.entries[map_index];
11923 const index = entry.acquire().unwrap() orelse return null;11923 const index = entry.value.unwrap() orelse return .none;
11924 if (entry.hash != hash) continue;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}
1192811928
src/codegen.zig+2
...@@ -993,6 +993,8 @@ pub fn genNavRef(...@@ -993,6 +993,8 @@ pub fn genNavRef(
993 },993 },
994 .link_once => unreachable,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 } else {998 } else {
997 const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target});999 const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target});
998 return .{ .fail = msg };1000 return .{ .fail = msg };
src/codegen/x86_64/Emit.zig+41-10
...@@ -89,6 +89,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -89,6 +89,7 @@ pub fn emitMir(emit: *Emit) Error!void {
89 }89 }
90 var reloc_info_buf: [2]RelocInfo = undefined;90 var reloc_info_buf: [2]RelocInfo = undefined;
91 var reloc_info_index: usize = 0;91 var reloc_info_index: usize = 0;
92 const ip = &emit.pt.zcu.intern_pool;
92 while (lowered_relocs.len > 0 and93 while (lowered_relocs.len > 0 and
93 lowered_relocs[0].lowered_inst_index == lowered_index) : ({94 lowered_relocs[0].lowered_inst_index == lowered_index) : ({
94 lowered_relocs = lowered_relocs[1..];95 lowered_relocs = lowered_relocs[1..];
...@@ -114,7 +115,6 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -114,7 +115,6 @@ pub fn emitMir(emit: *Emit) Error!void {
114 return error.EmitFail;115 return error.EmitFail;
115 },116 },
116 };117 };
117 const ip = &emit.pt.zcu.intern_pool;
118 break :target switch (ip.getNav(nav).status) {118 break :target switch (ip.getNav(nav).status) {
119 .unresolved => unreachable,119 .unresolved => unreachable,
120 .type_resolved => |type_resolved| .{120 .type_resolved => |type_resolved| .{
...@@ -175,6 +175,8 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -175,6 +175,8 @@ pub fn emitMir(emit: *Emit) Error!void {
175 coff_file.getAtom(atom).getSymbolIndex().?175 coff_file.getAtom(atom).getSymbolIndex().?
176 else |err|176 else |err|
177 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})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 else180 else
179 return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),181 return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
180 .is_extern = false,182 .is_extern = false,
...@@ -190,8 +192,13 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -190,8 +192,13 @@ pub fn emitMir(emit: *Emit) Error!void {
190 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)192 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
191 else if (emit.bin_file.cast(.coff)) |coff_file|193 else if (emit.bin_file.cast(.coff)) |coff_file|
192 try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt")194 try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt")
193 else195 else if (emit.bin_file.cast(.coff2)) |coff| @intFromEnum(try coff.globalSymbol(
194 return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),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 .is_extern = true,202 .is_extern = true,
196 .type = .symbol,203 .type = .symbol,
197 },204 },
...@@ -314,6 +321,18 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -314,6 +321,18 @@ pub fn emitMir(emit: *Emit) Error!void {
314 }, emit.lower.target), reloc_info),321 }, emit.lower.target), reloc_info),
315 else => unreachable,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 } else return emit.fail("TODO implement relocs for {s}", .{336 } else return emit.fail("TODO implement relocs for {s}", .{
318 @tagName(emit.bin_file.tag),337 @tagName(emit.bin_file.tag),
319 });338 });
...@@ -683,7 +702,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -683,7 +702,7 @@ pub fn emitMir(emit: *Emit) Error!void {
683 table_reloc.source_offset,702 table_reloc.source_offset,
684 @enumFromInt(emit.atom_index),703 @enumFromInt(emit.atom_index),
685 @as(i64, table_offset) + table_reloc.target_offset,704 @as(i64, table_offset) + table_reloc.target_offset,
686 .{ .x86_64 = .@"32" },705 .{ .X86_64 = .@"32" },
687 );706 );
688 for (emit.lower.mir.table) |entry| {707 for (emit.lower.mir.table) |entry| {
689 try elf.addReloc(708 try elf.addReloc(
...@@ -691,7 +710,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -691,7 +710,7 @@ pub fn emitMir(emit: *Emit) Error!void {
691 table_offset,710 table_offset,
692 @enumFromInt(emit.atom_index),711 @enumFromInt(emit.atom_index),
693 emit.code_offset_mapping.items[entry],712 emit.code_offset_mapping.items[entry],
694 .{ .x86_64 = .@"64" },713 .{ .X86_64 = .@"64" },
695 );714 );
696 table_offset += ptr_size;715 table_offset += ptr_size;
697 }716 }
...@@ -800,7 +819,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -800,7 +819,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
800 end_offset - 4,819 end_offset - 4,
801 @enumFromInt(reloc.target.index),820 @enumFromInt(reloc.target.index),
802 reloc.off,821 reloc.off,
803 .{ .x86_64 = .@"32" },822 .{ .X86_64 = .@"32" },
804 ) else if (emit.bin_file.cast(.coff)) |coff_file| {823 ) else if (emit.bin_file.cast(.coff)) |coff_file| {
805 const atom_index = coff_file.getAtomIndexForSymbol(824 const atom_index = coff_file.getAtomIndexForSymbol(
806 .{ .sym_index = emit.atom_index, .file = null },825 .{ .sym_index = emit.atom_index, .file = null },
...@@ -816,7 +835,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -816,7 +835,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
816 .pcrel = true,835 .pcrel = true,
817 .length = 2,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 .branch => if (emit.bin_file.cast(.elf)) |elf_file| {845 .branch => if (emit.bin_file.cast(.elf)) |elf_file| {
821 const zo = elf_file.zigObjectPtr().?;846 const zo = elf_file.zigObjectPtr().?;
822 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;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,7 +856,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
831 end_offset - 4,856 end_offset - 4,
832 @enumFromInt(reloc.target.index),857 @enumFromInt(reloc.target.index),
833 reloc.off - 4,858 reloc.off - 4,
834 .{ .x86_64 = .PC32 },859 .{ .X86_64 = .PC32 },
835 ) else if (emit.bin_file.cast(.macho)) |macho_file| {860 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
836 const zo = macho_file.getZigObject().?;861 const zo = macho_file.getZigObject().?;
837 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;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,7 +888,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
863 .pcrel = true,888 .pcrel = true,
864 .length = 2,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 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),898 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
868 }),899 }),
869 .tls => if (emit.bin_file.cast(.elf)) |elf_file| {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,7 +923,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
892 end_offset - 4,923 end_offset - 4,
893 @enumFromInt(reloc.target.index),924 @enumFromInt(reloc.target.index),
894 reloc.off,925 reloc.off,
895 .{ .x86_64 = .TPOFF32 },926 .{ .X86_64 = .TPOFF32 },
896 ) else if (emit.bin_file.cast(.macho)) |macho_file| {927 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
897 const zo = macho_file.getZigObject().?;928 const zo = macho_file.getZigObject().?;
898 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;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,6 +96,7 @@ pub const Env = enum {
96 .spirv_backend,96 .spirv_backend,
97 .lld_linker,97 .lld_linker,
98 .coff_linker,98 .coff_linker,
99 .coff2_linker,
99 .elf_linker,100 .elf_linker,
100 .elf2_linker,101 .elf2_linker,
101 .macho_linker,102 .macho_linker,
...@@ -284,6 +285,7 @@ pub const Feature = enum {...@@ -284,6 +285,7 @@ pub const Feature = enum {
284285
285 lld_linker,286 lld_linker,
286 coff_linker,287 coff_linker,
288 coff2_linker,
287 elf_linker,289 elf_linker,
288 elf2_linker,290 elf2_linker,
289 macho_linker,291 macho_linker,
src/link.zig+35-39
...@@ -610,27 +610,20 @@ pub const File = struct {...@@ -610,27 +610,20 @@ pub const File = struct {
610 }610 }
611 }611 }
612 }612 }
613 const output_mode = comp.config.output_mode;613 base.file = try emit.root_dir.handle.openFile(emit.sub_path, .{ .mode = .read_write });
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 });
620 },614 },
621 .elf2 => {615 .elf2, .coff2 => if (base.file == null) {
622 const elf = base.cast(.elf2).?;616 const mf = if (base.cast(.elf2)) |elf|
623 if (base.file == null) {617 &elf.mf
624 elf.mf.file = try base.emit.root_dir.handle.createFile(base.emit.sub_path, .{618 else if (base.cast(.coff2)) |coff|
625 .truncate = false,619 &coff.mf
626 .read = true,620 else
627 .mode = determineMode(comp.config.output_mode, comp.config.link_mode),621 unreachable;
628 });622 mf.file = try base.emit.root_dir.handle.openFile(base.emit.sub_path, .{
629 base.file = elf.mf.file;623 .mode = .read_write,
630 try elf.mf.ensureTotalCapacity(624 });
631 @intCast(elf.mf.nodes.items[0].location().resolve(&elf.mf)[1]),625 base.file = mf.file;
632 );626 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
633 }
634 },627 },
635 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),628 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
636 .plan9 => unreachable,629 .plan9 => unreachable,
...@@ -654,12 +647,9 @@ pub const File = struct {...@@ -654,12 +647,9 @@ pub const File = struct {
654 pub fn makeExecutable(base: *File) !void {647 pub fn makeExecutable(base: *File) !void {
655 dev.check(.make_executable);648 dev.check(.make_executable);
656 const comp = base.comp;649 const comp = base.comp;
657 const output_mode = comp.config.output_mode;650 switch (comp.config.output_mode) {
658 const link_mode = comp.config.link_mode;
659
660 switch (output_mode) {
661 .Obj => return,651 .Obj => return,
662 .Lib => switch (link_mode) {652 .Lib => switch (comp.config.link_mode) {
663 .static => return,653 .static => return,
664 .dynamic => {},654 .dynamic => {},
665 },655 },
...@@ -702,15 +692,18 @@ pub const File = struct {...@@ -702,15 +692,18 @@ pub const File = struct {
702 }692 }
703 }693 }
704 },694 },
705 .elf2 => {695 .elf2, .coff2 => if (base.file) |f| {
706 const elf = base.cast(.elf2).?;696 const mf = if (base.cast(.elf2)) |elf|
707 if (base.file) |f| {697 &elf.mf
708 elf.mf.unmap();698 else if (base.cast(.coff2)) |coff|
709 assert(elf.mf.file.handle == f.handle);699 &coff.mf
710 elf.mf.file = undefined;700 else
711 f.close();701 unreachable;
712 base.file = null;702 mf.unmap();
713 }703 assert(mf.file.handle == f.handle);
704 mf.file = undefined;
705 f.close();
706 base.file = null;
714 },707 },
715 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),708 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
716 .plan9 => unreachable,709 .plan9 => unreachable,
...@@ -828,7 +821,7 @@ pub const File = struct {...@@ -828,7 +821,7 @@ pub const File = struct {
828 .spirv => {},821 .spirv => {},
829 .goff, .xcoff => {},822 .goff, .xcoff => {},
830 .plan9 => unreachable,823 .plan9 => unreachable,
831 .elf2 => {},824 .elf2, .coff2 => {},
832 inline else => |tag| {825 inline else => |tag| {
833 dev.check(tag.devFeature());826 dev.check(tag.devFeature());
834 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id);827 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id);
...@@ -864,7 +857,7 @@ pub const File = struct {...@@ -864,7 +857,7 @@ pub const File = struct {
864 pub fn idle(base: *File, tid: Zcu.PerThread.Id) !bool {857 pub fn idle(base: *File, tid: Zcu.PerThread.Id) !bool {
865 switch (base.tag) {858 switch (base.tag) {
866 else => return false,859 else => return false,
867 inline .elf2 => |tag| {860 inline .elf2, .coff2 => |tag| {
868 dev.check(tag.devFeature());861 dev.check(tag.devFeature());
869 return @as(*tag.Type(), @fieldParentPtr("base", base)).idle(tid);862 return @as(*tag.Type(), @fieldParentPtr("base", base)).idle(tid);
870 },863 },
...@@ -874,7 +867,7 @@ pub const File = struct {...@@ -874,7 +867,7 @@ pub const File = struct {
874 pub fn updateErrorData(base: *File, pt: Zcu.PerThread) !void {867 pub fn updateErrorData(base: *File, pt: Zcu.PerThread) !void {
875 switch (base.tag) {868 switch (base.tag) {
876 else => {},869 else => {},
877 inline .elf2 => |tag| {870 inline .elf2, .coff2 => |tag| {
878 dev.check(tag.devFeature());871 dev.check(tag.devFeature());
879 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateErrorData(pt);872 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateErrorData(pt);
880 },873 },
...@@ -1155,7 +1148,7 @@ pub const File = struct {...@@ -1155,7 +1148,7 @@ pub const File = struct {
1155 if (base.zcu_object_basename != null) return;1148 if (base.zcu_object_basename != null) return;
11561149
1157 switch (base.tag) {1150 switch (base.tag) {
1158 inline .elf2, .wasm => |tag| {1151 inline .elf2, .coff2, .wasm => |tag| {
1159 dev.check(tag.devFeature());1152 dev.check(tag.devFeature());
1160 return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node);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,6 +1158,7 @@ pub const File = struct {
11651158
1166 pub const Tag = enum {1159 pub const Tag = enum {
1167 coff,1160 coff,
1161 coff2,
1168 elf,1162 elf,
1169 elf2,1163 elf2,
1170 macho,1164 macho,
...@@ -1179,6 +1173,7 @@ pub const File = struct {...@@ -1179,6 +1173,7 @@ pub const File = struct {
1179 pub fn Type(comptime tag: Tag) type {1173 pub fn Type(comptime tag: Tag) type {
1180 return switch (tag) {1174 return switch (tag) {
1181 .coff => Coff,1175 .coff => Coff,
1176 .coff2 => Coff2,
1182 .elf => Elf,1177 .elf => Elf,
1183 .elf2 => Elf2,1178 .elf2 => Elf2,
1184 .macho => MachO,1179 .macho => MachO,
...@@ -1194,7 +1189,7 @@ pub const File = struct {...@@ -1194,7 +1189,7 @@ pub const File = struct {
11941189
1195 fn fromObjectFormat(ofmt: std.Target.ObjectFormat, use_new_linker: bool) Tag {1190 fn fromObjectFormat(ofmt: std.Target.ObjectFormat, use_new_linker: bool) Tag {
1196 return switch (ofmt) {1191 return switch (ofmt) {
1197 .coff => .coff,1192 .coff => if (use_new_linker) .coff2 else .coff,
1198 .elf => if (use_new_linker) .elf2 else .elf,1193 .elf => if (use_new_linker) .elf2 else .elf,
1199 .macho => .macho,1194 .macho => .macho,
1200 .wasm => .wasm,1195 .wasm => .wasm,
...@@ -1280,6 +1275,7 @@ pub const File = struct {...@@ -1280,6 +1275,7 @@ pub const File = struct {
1280 pub const Lld = @import("link/Lld.zig");1275 pub const Lld = @import("link/Lld.zig");
1281 pub const C = @import("link/C.zig");1276 pub const C = @import("link/C.zig");
1282 pub const Coff = @import("link/Coff.zig");1277 pub const Coff = @import("link/Coff.zig");
1278 pub const Coff2 = @import("link/Coff2.zig");
1283 pub const Elf = @import("link/Elf.zig");1279 pub const Elf = @import("link/Elf.zig");
1284 pub const Elf2 = @import("link/Elf2.zig");1280 pub const Elf2 = @import("link/Elf2.zig");
1285 pub const MachO = @import("link/MachO.zig");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,11 +125,11 @@ const UavTable = std.AutoHashMapUnmanaged(InternPool.Index, AvMetadata);
125const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));125const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
126const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));126const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
127127
128const default_file_alignment: u16 = 0x200;128pub const default_file_alignment: u16 = 0x200;
129const default_size_of_stack_reserve: u32 = 0x1000000;129pub const default_size_of_stack_reserve: u32 = 0x1000000;
130const default_size_of_stack_commit: u32 = 0x1000;130pub const default_size_of_stack_commit: u32 = 0x1000;
131const default_size_of_heap_reserve: u32 = 0x100000;131pub const default_size_of_heap_reserve: u32 = 0x100000;
132const default_size_of_heap_commit: u32 = 0x1000;132pub const default_size_of_heap_commit: u32 = 0x1000;
133133
134const Section = struct {134const Section = struct {
135 header: coff_util.SectionHeader,135 header: coff_util.SectionHeader,
...@@ -334,51 +334,51 @@ pub fn createEmpty(...@@ -334,51 +334,51 @@ pub fn createEmpty(
334 if (coff.text_section_index == null) {334 if (coff.text_section_index == null) {
335 const file_size: u32 = @intCast(options.program_code_size_hint);335 const file_size: u32 = @intCast(options.program_code_size_hint);
336 coff.text_section_index = try coff.allocateSection(".text", file_size, .{336 coff.text_section_index = try coff.allocateSection(".text", file_size, .{
337 .CNT_CODE = 1,337 .CNT_CODE = true,
338 .MEM_EXECUTE = 1,338 .MEM_EXECUTE = true,
339 .MEM_READ = 1,339 .MEM_READ = true,
340 });340 });
341 }341 }
342342
343 if (coff.got_section_index == null) {343 if (coff.got_section_index == null) {
344 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();344 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();
345 coff.got_section_index = try coff.allocateSection(".got", file_size, .{345 coff.got_section_index = try coff.allocateSection(".got", file_size, .{
346 .CNT_INITIALIZED_DATA = 1,346 .CNT_INITIALIZED_DATA = true,
347 .MEM_READ = 1,347 .MEM_READ = true,
348 });348 });
349 }349 }
350350
351 if (coff.rdata_section_index == null) {351 if (coff.rdata_section_index == null) {
352 const file_size: u32 = coff.page_size;352 const file_size: u32 = coff.page_size;
353 coff.rdata_section_index = try coff.allocateSection(".rdata", file_size, .{353 coff.rdata_section_index = try coff.allocateSection(".rdata", file_size, .{
354 .CNT_INITIALIZED_DATA = 1,354 .CNT_INITIALIZED_DATA = true,
355 .MEM_READ = 1,355 .MEM_READ = true,
356 });356 });
357 }357 }
358358
359 if (coff.data_section_index == null) {359 if (coff.data_section_index == null) {
360 const file_size: u32 = coff.page_size;360 const file_size: u32 = coff.page_size;
361 coff.data_section_index = try coff.allocateSection(".data", file_size, .{361 coff.data_section_index = try coff.allocateSection(".data", file_size, .{
362 .CNT_INITIALIZED_DATA = 1,362 .CNT_INITIALIZED_DATA = true,
363 .MEM_READ = 1,363 .MEM_READ = true,
364 .MEM_WRITE = 1,364 .MEM_WRITE = true,
365 });365 });
366 }366 }
367367
368 if (coff.idata_section_index == null) {368 if (coff.idata_section_index == null) {
369 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();369 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();
370 coff.idata_section_index = try coff.allocateSection(".idata", file_size, .{370 coff.idata_section_index = try coff.allocateSection(".idata", file_size, .{
371 .CNT_INITIALIZED_DATA = 1,371 .CNT_INITIALIZED_DATA = true,
372 .MEM_READ = 1,372 .MEM_READ = true,
373 });373 });
374 }374 }
375375
376 if (coff.reloc_section_index == null) {376 if (coff.reloc_section_index == null) {
377 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff_util.BaseRelocation);377 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff_util.BaseRelocation);
378 coff.reloc_section_index = try coff.allocateSection(".reloc", file_size, .{378 coff.reloc_section_index = try coff.allocateSection(".reloc", file_size, .{
379 .CNT_INITIALIZED_DATA = 1,379 .CNT_INITIALIZED_DATA = true,
380 .MEM_DISCARDABLE = 1,380 .MEM_DISCARDABLE = true,
381 .MEM_READ = 1,381 .MEM_READ = true,
382 });382 });
383 }383 }
384384
...@@ -477,7 +477,7 @@ pub fn deinit(coff: *Coff) void {...@@ -477,7 +477,7 @@ pub fn deinit(coff: *Coff) void {
477 coff.base_relocs.deinit(gpa);477 coff.base_relocs.deinit(gpa);
478}478}
479479
480fn allocateSection(coff: *Coff, name: []const u8, size: u32, flags: coff_util.SectionHeaderFlags) !u16 {480fn allocateSection(coff: *Coff, name: []const u8, size: u32, flags: coff_util.SectionHeader.Flags) !u16 {
481 const index = @as(u16, @intCast(coff.sections.slice().len));481 const index = @as(u16, @intCast(coff.sections.slice().len));
482 const off = coff.findFreeSpace(size, default_file_alignment);482 const off = coff.findFreeSpace(size, default_file_alignment);
483 // Memory is always allocated in sequence483 // Memory is always allocated in sequence
...@@ -836,7 +836,7 @@ fn writeAtom(coff: *Coff, atom_index: Atom.Index, code: []u8, resolve_relocs: bo...@@ -836,7 +836,7 @@ fn writeAtom(coff: *Coff, atom_index: Atom.Index, code: []u8, resolve_relocs: bo
836 try debugMem(gpa, handle, pvaddr, mem_code);836 try debugMem(gpa, handle, pvaddr, mem_code);
837 }837 }
838838
839 if (section.header.flags.MEM_WRITE == 0) {839 if (!section.header.flags.MEM_WRITE) {
840 writeMemProtected(handle, pvaddr, mem_code) catch |err| {840 writeMemProtected(handle, pvaddr, mem_code) catch |err| {
841 log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)});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,21 +2227,21 @@ fn writeHeader(coff: *Coff) !void {
2227 mem.writeInt(u32, buffer.writer.buffer[0x3c..][0..4], msdos_stub.len, .little);2227 mem.writeInt(u32, buffer.writer.buffer[0x3c..][0..4], msdos_stub.len, .little);
22282228
2229 writer.writeAll("PE\x00\x00") catch unreachable;2229 writer.writeAll("PE\x00\x00") catch unreachable;
2230 var flags = coff_util.CoffHeaderFlags{2230 var flags: coff_util.Header.Flags = .{
2231 .EXECUTABLE_IMAGE = 1,2231 .EXECUTABLE_IMAGE = true,
2232 .DEBUG_STRIPPED = 1, // TODO2232 .DEBUG_STRIPPED = true, // TODO
2233 };2233 };
2234 switch (coff.ptr_width) {2234 switch (coff.ptr_width) {
2235 .p32 => flags.@"32BIT_MACHINE" = 1,2235 .p32 => flags.@"32BIT_MACHINE" = true,
2236 .p64 => flags.LARGE_ADDRESS_AWARE = 1,2236 .p64 => flags.LARGE_ADDRESS_AWARE = true,
2237 }2237 }
2238 if (coff.base.comp.config.output_mode == .Lib and coff.base.comp.config.link_mode == .dynamic) {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 }
22412241
2242 const timestamp = if (coff.repro) 0 else std.time.timestamp();2242 const timestamp = if (coff.repro) 0 else std.time.timestamp();
2243 const size_of_optional_header = @as(u16, @intCast(coff.getOptionalHeaderSize() + coff.getDataDirectoryHeadersSize()));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 .machine = target.toCoffMachine(),2245 .machine = target.toCoffMachine(),
2246 .number_of_sections = @as(u16, @intCast(coff.sections.slice().len)), // TODO what if we prune a section2246 .number_of_sections = @as(u16, @intCast(coff.sections.slice().len)), // TODO what if we prune a section
2247 .time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))),2247 .time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))),
...@@ -2254,10 +2254,10 @@ fn writeHeader(coff: *Coff) !void {...@@ -2254,10 +2254,10 @@ fn writeHeader(coff: *Coff) !void {
2254 writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;2254 writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;
22552255
2256 const dll_flags: coff_util.DllFlags = .{2256 const dll_flags: coff_util.DllFlags = .{
2257 .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all?2257 .HIGH_ENTROPY_VA = true, // TODO do we want to permit non-PIE builds at all?
2258 .DYNAMIC_BASE = 1,2258 .DYNAMIC_BASE = true,
2259 .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app2259 .TERMINAL_SERVER_AWARE = true, // We are not a legacy app
2260 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention2260 .NX_COMPAT = true, // We are compatible with Data Execution Prevention
2261 };2261 };
2262 const subsystem: coff_util.Subsystem = .WINDOWS_CUI;2262 const subsystem: coff_util.Subsystem = .WINDOWS_CUI;
2263 const size_of_image: u32 = coff.getSizeOfImage();2263 const size_of_image: u32 = coff.getSizeOfImage();
...@@ -2269,13 +2269,13 @@ fn writeHeader(coff: *Coff) !void {...@@ -2269,13 +2269,13 @@ fn writeHeader(coff: *Coff) !void {
2269 var size_of_initialized_data: u32 = 0;2269 var size_of_initialized_data: u32 = 0;
2270 var size_of_uninitialized_data: u32 = 0;2270 var size_of_uninitialized_data: u32 = 0;
2271 for (coff.sections.items(.header)) |header| {2271 for (coff.sections.items(.header)) |header| {
2272 if (header.flags.CNT_CODE == 1) {2272 if (header.flags.CNT_CODE) {
2273 size_of_code += header.size_of_raw_data;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 size_of_initialized_data += header.size_of_raw_data;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 size_of_uninitialized_data += header.size_of_raw_data;2279 size_of_uninitialized_data += header.size_of_raw_data;
2280 }2280 }
2281 }2281 }
...@@ -2283,7 +2283,7 @@ fn writeHeader(coff: *Coff) !void {...@@ -2283,7 +2283,7 @@ fn writeHeader(coff: *Coff) !void {
2283 switch (coff.ptr_width) {2283 switch (coff.ptr_width) {
2284 .p32 => {2284 .p32 => {
2285 var opt_header = coff_util.OptionalHeaderPE32{2285 var opt_header = coff_util.OptionalHeaderPE32{
2286 .magic = coff_util.IMAGE_NT_OPTIONAL_HDR32_MAGIC,2286 .magic = .PE32,
2287 .major_linker_version = 0,2287 .major_linker_version = 0,
2288 .minor_linker_version = 0,2288 .minor_linker_version = 0,
2289 .size_of_code = size_of_code,2289 .size_of_code = size_of_code,
...@@ -2318,7 +2318,7 @@ fn writeHeader(coff: *Coff) !void {...@@ -2318,7 +2318,7 @@ fn writeHeader(coff: *Coff) !void {
2318 },2318 },
2319 .p64 => {2319 .p64 => {
2320 var opt_header = coff_util.OptionalHeaderPE64{2320 var opt_header = coff_util.OptionalHeaderPE64{
2321 .magic = coff_util.IMAGE_NT_OPTIONAL_HDR64_MAGIC,2321 .magic = .@"PE32+",
2322 .major_linker_version = 0,2322 .major_linker_version = 0,
2323 .minor_linker_version = 0,2323 .minor_linker_version = 0,
2324 .size_of_code = size_of_code,2324 .size_of_code = size_of_code,
...@@ -2422,7 +2422,7 @@ fn allocatedVirtualSize(coff: *Coff, start: u32) u32 {...@@ -2422,7 +2422,7 @@ fn allocatedVirtualSize(coff: *Coff, start: u32) u32 {
24222422
2423fn getSizeOfHeaders(coff: Coff) u32 {2423fn getSizeOfHeaders(coff: Coff) u32 {
2424 const msdos_hdr_size = msdos_stub.len + 4;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 coff.getDataDirectoryHeadersSize() + coff.getSectionHeadersSize()));2426 coff.getDataDirectoryHeadersSize() + coff.getSectionHeadersSize()));
2427}2427}
24282428
...@@ -2443,7 +2443,7 @@ fn getSectionHeadersSize(coff: Coff) u32 {...@@ -2443,7 +2443,7 @@ fn getSectionHeadersSize(coff: Coff) u32 {
24432443
2444fn getDataDirectoryHeadersOffset(coff: Coff) u32 {2444fn getDataDirectoryHeadersOffset(coff: Coff) u32 {
2445 const msdos_hdr_size = msdos_stub.len + 4;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}
24482448
2449fn getSectionHeadersOffset(coff: Coff) u32 {2449fn getSectionHeadersOffset(coff: Coff) u32 {
...@@ -3116,7 +3116,7 @@ fn pwriteAll(coff: *Coff, bytes: []const u8, offset: u64) error{LinkFailure}!voi...@@ -3116,7 +3116,7 @@ fn pwriteAll(coff: *Coff, bytes: []const u8, offset: u64) error{LinkFailure}!voi
3116/// A "page" is 512 bytes.3116/// A "page" is 512 bytes.
3117/// A "long" is 4 bytes.3117/// A "long" is 4 bytes.
3118/// A "word" is 2 bytes.3118/// A "word" is 2 bytes.
3119const msdos_stub: [120]u8 = .{3119pub const msdos_stub: [120]u8 = .{
3120 'M', 'Z', // Magic number. Stands for Mark Zbikowski (designer of the MS-DOS executable format).3120 'M', 'Z', // Magic number. Stands for Mark Zbikowski (designer of the MS-DOS executable format).
3121 0x78, 0x00, // Number of bytes in the last page. This matches the size of this entire MS-DOS stub.3121 0x78, 0x00, // Number of bytes in the last page. This matches the size of this entire MS-DOS stub.
3122 0x01, 0x00, // Number of pages.3122 0x01, 0x00, // Number of pages.
src/link/Coff2.zig created+2128
...@@ -0,0 +1,2128 @@
1base: link.File,
2endian: std.builtin.Endian,
3mf: MappedFile,
4nodes: std.MultiArrayList(Node),
5import_table: ImportTable,
6strings: std.HashMapUnmanaged(
7 u32,
8 void,
9 std.hash_map.StringIndexContext,
10 std.hash_map.default_max_load_percentage,
11),
12string_bytes: std.ArrayList(u8),
13section_table: std.ArrayList(Symbol.Index),
14symbol_table: std.ArrayList(Symbol),
15globals: std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index),
16global_pending_index: u32,
17navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index),
18uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
19lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {
20 map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
21 pending_index: u32,
22}),
23pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
24 alignment: InternPool.Alignment,
25 src_loc: Zcu.LazySrcLoc,
26}),
27relocs: std.ArrayList(Reloc),
28/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.
29entry_hack: Symbol.Index,
30
31pub 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
141pub 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
160pub 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
190pub 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
219pub const GlobalName = struct { name: String, lib_name: String.Optional };
220
221pub 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
314pub 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
477pub 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}
485pub 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}
493fn 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
586pub 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
604fn 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
860fn getNode(coff: *const Coff, ni: MappedFile.Node.Index) Node {
861 return coff.nodes.get(@intFromEnum(ni));
862}
863fn 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
878pub inline fn targetEndian(coff: *const Coff) std.builtin.Endian {
879 return coff.endian;
880}
881fn 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}
892fn 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
908pub fn headerPtr(coff: *Coff) *std.coff.Header {
909 return @ptrCast(@alignCast(Node.known.coff_header.slice(&coff.mf)));
910}
911
912pub 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
918pub const OptionalHeaderPtr = union(std.coff.OptionalHeader.Magic) {
919 PE32: *std.coff.OptionalHeader.PE32,
920 @"PE32+": *std.coff.OptionalHeader.@"PE32+",
921};
922pub 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}
933pub 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
942pub fn dataDirectoriesSlice(coff: *Coff) []std.coff.ImageDataDirectory {
943 return @ptrCast(@alignCast(Node.known.data_directories.slice(&coff.mf)));
944}
945
946pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader {
947 return @ptrCast(@alignCast(Node.known.section_table.slice(&coff.mf)));
948}
949
950fn 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
963fn initSymbolAssumeCapacity(coff: *Coff) !Symbol.Index {
964 const si = coff.addSymbolAssumeCapacity();
965 return si;
966}
967
968fn 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
986fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional {
987 return (try coff.getOrPutString(string orelse return .none)).toOptional();
988}
989
990pub 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
1004fn 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}
1011pub 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
1022fn 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}
1029pub 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
1034pub 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
1045pub 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
1054pub 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
1062pub 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
1077fn 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
1150pub 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
1178pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) void {
1179 _ = coff;
1180 _ = prog_node;
1181}
1182
1183pub 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}
1192fn 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
1248pub 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
1279pub 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}
1298fn 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
1364pub 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
1375pub 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
1408pub 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
1495fn 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
1518fn 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
1571fn 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
1734fn 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
1782fn 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
1866fn 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
1921fn 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
1945pub 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}
1956fn 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
2008pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void {
2009 _ = coff;
2010 _ = exported;
2011 _ = name;
2012}
2013
2014pub 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
2020pub 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
2114const assert = std.debug.assert;
2115const builtin = @import("builtin");
2116const codegen = @import("../codegen.zig");
2117const Compilation = @import("../Compilation.zig");
2118const Coff = @This();
2119const InternPool = @import("../InternPool.zig");
2120const link = @import("../link.zig");
2121const log = std.log.scoped(.link);
2122const MappedFile = @import("MappedFile.zig");
2123const native_endian = builtin.cpu.arch.endian();
2124const std = @import("std");
2125const target_util = @import("../target.zig");
2126const Type = @import("../Type.zig");
2127const Value = @import("../Value.zig");
2128const Zcu = @import("../Zcu.zig");
src/link/Elf2.zig+325-303
...@@ -11,7 +11,7 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {...@@ -11,7 +11,7 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {
11 map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),11 map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
12 pending_index: u32,12 pending_index: u32,
13}),13}),
14pending_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct {14pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
15 alignment: InternPool.Alignment,15 alignment: InternPool.Alignment,
16 src_loc: Zcu.LazySrcLoc,16 src_loc: Zcu.LazySrcLoc,
17}),17}),
...@@ -25,10 +25,65 @@ pub const Node = union(enum) {...@@ -25,10 +25,65 @@ pub const Node = union(enum) {
25 shdr,25 shdr,
26 segment: u32,26 segment: u32,
27 section: Symbol.Index,27 section: Symbol.Index,
28 nav: InternPool.Nav.Index,28 nav: NavMapIndex,
29 uav: InternPool.Index,29 uav: UavMapIndex,
30 lazy_code: InternPool.Index,30 lazy_code: LazyMapRef.Index(.code),
31 lazy_const_data: InternPool.Index,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 };
3287
33 pub const Tag = @typeInfo(Node).@"union".tag_type.?;88 pub const Tag = @typeInfo(Node).@"union".tag_type.?;
3489
...@@ -43,11 +98,7 @@ pub const Node = union(enum) {...@@ -43,11 +98,7 @@ pub const Node = union(enum) {
43 seg_text,98 seg_text,
44 seg_data,99 seg_data,
45 };100 };
46 var mut_known: std.enums.EnumFieldStruct(101 var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined;
47 Known,
48 MappedFile.Node.Index,
49 null,
50 ) = undefined;
51 for (@typeInfo(Known).@"enum".fields) |field|102 for (@typeInfo(Known).@"enum".fields) |field|
52 @field(mut_known, field.name) = @enumFromInt(field.value);103 @field(mut_known, field.name) = @enumFromInt(field.value);
53 break :known mut_known;104 break :known mut_known;
...@@ -223,10 +274,10 @@ pub const Reloc = extern struct {...@@ -223,10 +274,10 @@ pub const Reloc = extern struct {
223 addend: i64,274 addend: i64,
224275
225 pub const Type = extern union {276 pub const Type = extern union {
226 x86_64: std.elf.R_X86_64,277 X86_64: std.elf.R_X86_64,
227 aarch64: std.elf.R_AARCH64,278 AARCH64: std.elf.R_AARCH64,
228 riscv: std.elf.R_RISCV,279 RISCV: std.elf.R_RISCV,
229 ppc64: std.elf.R_PPC64,280 PPC64: std.elf.R_PPC64,
230 };281 };
231282
232 pub const Index = enum(u32) {283 pub const Index = enum(u32) {
...@@ -239,7 +290,7 @@ pub const Reloc = extern struct {...@@ -239,7 +290,7 @@ pub const Reloc = extern struct {
239 };290 };
240291
241 pub fn apply(reloc: *const Reloc, elf: *Elf) void {292 pub fn apply(reloc: *const Reloc, elf: *Elf) void {
242 const target_endian = elf.endian();293 const target_endian = elf.targetEndian();
243 switch (reloc.loc.get(elf).ni) {294 switch (reloc.loc.get(elf).ni) {
244 .none => return,295 .none => return,
245 else => |ni| if (ni.hasMoved(&elf.mf)) return,296 else => |ni| if (ni.hasMoved(&elf.mf)) return,
...@@ -274,7 +325,7 @@ pub const Reloc = extern struct {...@@ -274,7 +325,7 @@ pub const Reloc = extern struct {
274 ) +% @as(u64, @bitCast(reloc.addend));325 ) +% @as(u64, @bitCast(reloc.addend));
275 switch (elf.ehdrField(.machine)) {326 switch (elf.ehdrField(.machine)) {
276 else => |machine| @panic(@tagName(machine)),327 else => |machine| @panic(@tagName(machine)),
277 .X86_64 => switch (reloc.type.x86_64) {328 .X86_64 => switch (reloc.type.X86_64) {
278 else => |kind| @panic(@tagName(kind)),329 else => |kind| @panic(@tagName(kind)),
279 .@"64" => std.mem.writeInt(330 .@"64" => std.mem.writeInt(
280 u64,331 u64,
...@@ -394,37 +445,7 @@ fn create(...@@ -394,37 +445,7 @@ fn create(
394 },445 },
395 .Obj => .REL,446 .Obj => .REL,
396 };447 };
397 const machine: std.elf.EM = switch (target.cpu.arch) {448 const machine = target.toElfMachine();
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 };
428 const maybe_interp = switch (comp.config.output_mode) {449 const maybe_interp = switch (comp.config.output_mode) {
429 .Exe, .Lib => switch (comp.config.link_mode) {450 .Exe, .Lib => switch (comp.config.link_mode) {
430 .static => null,451 .static => null,
...@@ -479,7 +500,7 @@ fn create(...@@ -479,7 +500,7 @@ fn create(
479500
480 switch (class) {501 switch (class) {
481 .NONE, _ => unreachable,502 .NONE, _ => unreachable,
482 inline .@"32", .@"64" => |ct_class| try elf.initHeaders(503 inline else => |ct_class| try elf.initHeaders(
483 ct_class,504 ct_class,
484 data,505 data,
485 osabi,506 osabi,
...@@ -567,30 +588,31 @@ fn initHeaders(...@@ -567,30 +588,31 @@ fn initHeaders(
567 .fixed = true,588 .fixed = true,
568 }));589 }));
569 elf.nodes.appendAssumeCapacity(.ehdr);590 elf.nodes.appendAssumeCapacity(.ehdr);
570591 {
571 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf)));592 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf)));
572 const EI = std.elf.EI;593 const EI = std.elf.EI;
573 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);594 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);
574 ehdr.ident[EI.CLASS] = @intFromEnum(class);595 ehdr.ident[EI.CLASS] = @intFromEnum(class);
575 ehdr.ident[EI.DATA] = @intFromEnum(data);596 ehdr.ident[EI.DATA] = @intFromEnum(data);
576 ehdr.ident[EI.VERSION] = 1;597 ehdr.ident[EI.VERSION] = 1;
577 ehdr.ident[EI.OSABI] = @intFromEnum(osabi);598 ehdr.ident[EI.OSABI] = @intFromEnum(osabi);
578 ehdr.ident[EI.ABIVERSION] = 0;599 ehdr.ident[EI.ABIVERSION] = 0;
579 @memset(ehdr.ident[EI.PAD..], 0);600 @memset(ehdr.ident[EI.PAD..], 0);
580 ehdr.type = @"type";601 ehdr.type = @"type";
581 ehdr.machine = machine;602 ehdr.machine = machine;
582 ehdr.version = 1;603 ehdr.version = 1;
583 ehdr.entry = 0;604 ehdr.entry = 0;
584 ehdr.phoff = 0;605 ehdr.phoff = 0;
585 ehdr.shoff = 0;606 ehdr.shoff = 0;
586 ehdr.flags = 0;607 ehdr.flags = 0;
587 ehdr.ehsize = @sizeOf(ElfN.Ehdr);608 ehdr.ehsize = @sizeOf(ElfN.Ehdr);
588 ehdr.phentsize = @sizeOf(ElfN.Phdr);609 ehdr.phentsize = @sizeOf(ElfN.Phdr);
589 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);610 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);
590 ehdr.shentsize = @sizeOf(ElfN.Shdr);611 ehdr.shentsize = @sizeOf(ElfN.Shdr);
591 ehdr.shnum = 1;612 ehdr.shnum = 1;
592 ehdr.shstrndx = 0;613 ehdr.shstrndx = 0;
593 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);614 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
615 }
594616
595 const phdr_ni = Node.known.phdr;617 const phdr_ni = Node.known.phdr;
596 assert(phdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{618 assert(phdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{
...@@ -750,7 +772,10 @@ fn initHeaders(...@@ -750,7 +772,10 @@ fn initHeaders(
750 },772 },
751 .shndx = std.elf.SHN_UNDEF,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 assert(try elf.addSection(seg_rodata_ni, .{779 assert(try elf.addSection(seg_rodata_ni, .{
755 .type = std.elf.SHT_STRTAB,780 .type = std.elf.SHT_STRTAB,
756 .addralign = elf.mf.flags.block_size,781 .addralign = elf.mf.flags.block_size,
...@@ -821,6 +846,24 @@ fn getNode(elf: *Elf, ni: MappedFile.Node.Index) Node {...@@ -821,6 +846,24 @@ fn getNode(elf: *Elf, ni: MappedFile.Node.Index) Node {
821 return elf.nodes.get(@intFromEnum(ni));846 return elf.nodes.get(@intFromEnum(ni));
822}847}
823848
849pub fn identClass(elf: *Elf) std.elf.CLASS {
850 return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]);
851}
852
853pub fn identData(elf: *Elf) std.elf.DATA {
854 return @enumFromInt(elf.mf.contents[std.elf.EI.DATA]);
855}
856fn endianForData(data: std.elf.DATA) std.builtin.Endian {
857 return switch (data) {
858 .NONE, _ => unreachable,
859 .@"2LSB" => .little,
860 .@"2MSB" => .big,
861 };
862}
863pub fn targetEndian(elf: *Elf) std.builtin.Endian {
864 return endianForData(elf.identData());
865}
866
824pub const EhdrPtr = union(std.elf.CLASS) {867pub const EhdrPtr = union(std.elf.CLASS) {
825 NONE: noreturn,868 NONE: noreturn,
826 @"32": *std.elf.Elf32.Ehdr,869 @"32": *std.elf.Elf32.Ehdr,
...@@ -830,7 +873,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr {...@@ -830,7 +873,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr {
830 const slice = Node.known.ehdr.slice(&elf.mf);873 const slice = Node.known.ehdr.slice(&elf.mf);
831 return switch (elf.identClass()) {874 return switch (elf.identClass()) {
832 .NONE, _ => unreachable,875 .NONE, _ => unreachable,
833 inline .@"32", .@"64" => |class| @unionInit(876 inline else => |class| @unionInit(
834 EhdrPtr,877 EhdrPtr,
835 @tagName(class),878 @tagName(class),
836 @ptrCast(@alignCast(slice)),879 @ptrCast(@alignCast(slice)),
...@@ -841,35 +884,15 @@ pub fn ehdrField(...@@ -841,35 +884,15 @@ pub fn ehdrField(
841 elf: *Elf,884 elf: *Elf,
842 comptime field: enum { type, machine },885 comptime field: enum { type, machine },
843) @FieldType(std.elf.Elf32.Ehdr, @tagName(field)) {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 return @enumFromInt(std.mem.toNative(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 @intFromEnum(switch (elf.ehdrPtr()) {889 @intFromEnum(switch (elf.ehdrPtr()) {
849 inline else => |ehdr| @field(ehdr, @tagName(field)),890 inline else => |ehdr| @field(ehdr, @tagName(field)),
850 }),891 }),
851 elf.endian(),892 elf.targetEndian(),
852 ));893 ));
853}894}
854895
855pub fn identClass(elf: *Elf) std.elf.CLASS {
856 return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]);
857}
858
859pub fn identData(elf: *Elf) std.elf.DATA {
860 return @enumFromInt(elf.mf.contents[std.elf.EI.DATA]);
861}
862fn endianForData(data: std.elf.DATA) std.builtin.Endian {
863 return switch (data) {
864 .NONE, _ => unreachable,
865 .@"2LSB" => .little,
866 .@"2MSB" => .big,
867 };
868}
869pub fn endian(elf: *Elf) std.builtin.Endian {
870 return endianForData(elf.identData());
871}
872
873fn baseAddrForType(@"type": std.elf.ET) u64 {896fn baseAddrForType(@"type": std.elf.ET) u64 {
874 return switch (@"type") {897 return switch (@"type") {
875 else => 0,898 else => 0,
...@@ -889,7 +912,7 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice {...@@ -889,7 +912,7 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice {
889 const slice = Node.known.phdr.slice(&elf.mf);912 const slice = Node.known.phdr.slice(&elf.mf);
890 return switch (elf.identClass()) {913 return switch (elf.identClass()) {
891 .NONE, _ => unreachable,914 .NONE, _ => unreachable,
892 inline .@"32", .@"64" => |class| @unionInit(915 inline else => |class| @unionInit(
893 PhdrSlice,916 PhdrSlice,
894 @tagName(class),917 @tagName(class),
895 @ptrCast(@alignCast(slice)),918 @ptrCast(@alignCast(slice)),
...@@ -906,7 +929,7 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice {...@@ -906,7 +929,7 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice {
906 const slice = Node.known.shdr.slice(&elf.mf);929 const slice = Node.known.shdr.slice(&elf.mf);
907 return switch (elf.identClass()) {930 return switch (elf.identClass()) {
908 .NONE, _ => unreachable,931 .NONE, _ => unreachable,
909 inline .@"32", .@"64" => |class| @unionInit(932 inline else => |class| @unionInit(
910 ShdrSlice,933 ShdrSlice,
911 @tagName(class),934 @tagName(class),
912 @ptrCast(@alignCast(slice)),935 @ptrCast(@alignCast(slice)),
...@@ -923,7 +946,7 @@ pub fn symSlice(elf: *Elf) SymSlice {...@@ -923,7 +946,7 @@ pub fn symSlice(elf: *Elf) SymSlice {
923 const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf);946 const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf);
924 return switch (elf.identClass()) {947 return switch (elf.identClass()) {
925 .NONE, _ => unreachable,948 .NONE, _ => unreachable,
926 inline .@"32", .@"64" => |class| @unionInit(949 inline else => |class| @unionInit(
927 SymSlice,950 SymSlice,
928 @tagName(class),951 @tagName(class),
929 @ptrCast(@alignCast(slice)),952 @ptrCast(@alignCast(slice)),
...@@ -942,7 +965,7 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {...@@ -942,7 +965,7 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
942 };965 };
943}966}
944967
945fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index {968fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {
946 defer elf.symtab.addOneAssumeCapacity().* = .{969 defer elf.symtab.addOneAssumeCapacity().* = .{
947 .ni = .none,970 .ni = .none,
948 .loc_relocs = .none,971 .loc_relocs = .none,
...@@ -953,30 +976,27 @@ fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index {...@@ -953,30 +976,27 @@ fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index {
953}976}
954977
955fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index {978fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index {
956 const si = try elf.addSymbolAssumeCapacity();979 const si = elf.addSymbolAssumeCapacity();
957 try si.init(elf, opts);980 try si.init(elf, opts);
958 return si;981 return si;
959}982}
960983
961pub fn globalSymbol(984pub fn globalSymbol(elf: *Elf, opts: struct {
962 elf: *Elf,985 name: []const u8,
963 opts: struct {986 type: std.elf.STT,
964 name: []const u8,987 bind: std.elf.STB = .GLOBAL,
965 type: std.elf.STT,988 visibility: std.elf.STV = .DEFAULT,
966 bind: std.elf.STB = .GLOBAL,989}) !Symbol.Index {
967 visibility: std.elf.STV = .DEFAULT,
968 },
969) !Symbol.Index {
970 const gpa = elf.base.comp.gpa;990 const gpa = elf.base.comp.gpa;
971 try elf.symtab.ensureUnusedCapacity(gpa, 1);991 try elf.symtab.ensureUnusedCapacity(gpa, 1);
972 const sym_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));992 const global_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(.{993 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
974 .name = opts.name,994 .name = opts.name,
975 .type = opts.type,995 .type = opts.type,
976 .bind = opts.bind,996 .bind = opts.bind,
977 .visibility = opts.visibility,997 .visibility = opts.visibility,
978 });998 });
979 return sym_gop.value_ptr.*;999 return global_gop.value_ptr.*;
980}1000}
9811001
982fn navType(1002fn navType(
...@@ -1008,8 +1028,19 @@ fn navType(...@@ -1008,8 +1028,19 @@ fn navType(
1008 },1028 },
1009 };1029 };
1010}1030}
1011pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {1031fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex {
1012 const gpa = zcu.gpa;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}
1043pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {
1013 const ip = &zcu.intern_pool;1044 const ip = &zcu.intern_pool;
1014 const nav = ip.getNav(nav_index);1045 const nav = ip.getNav(nav_index);
1015 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{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,40 +1058,37 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.
1027 .protected => .PROTECTED,1058 .protected => .PROTECTED,
1028 },1059 },
1029 });1060 });
1030 try elf.symtab.ensureUnusedCapacity(gpa, 1);1061 const nmi = try elf.navMapIndex(zcu, nav_index);
1031 const sym_gop = try elf.navs.getOrPut(gpa, nav_index);1062 return nmi.symbol(elf);
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.*;
1039}1063}
10401064
1041pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index {1065fn uavMapIndex(elf: *Elf, uav_val: InternPool.Index) !Node.UavMapIndex {
1042 const gpa = elf.base.comp.gpa;1066 const gpa = elf.base.comp.gpa;
1043 try elf.symtab.ensureUnusedCapacity(gpa, 1);1067 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1044 const sym_gop = try elf.uavs.getOrPut(gpa, uav_val);1068 const uav_gop = try elf.uavs.getOrPut(gpa, uav_val);
1045 if (!sym_gop.found_existing)1069 if (!uav_gop.found_existing)
1046 sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT });1070 uav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT });
1047 return sym_gop.value_ptr.*;1071 return @enumFromInt(uav_gop.index);
1072}
1073pub 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}
10491077
1050pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {1078pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
1051 const gpa = elf.base.comp.gpa;1079 const gpa = elf.base.comp.gpa;
1052 try elf.symtab.ensureUnusedCapacity(gpa, 1);1080 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1053 const sym_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);1081 const lazy_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);
1054 if (!sym_gop.found_existing) {1082 if (!lazy_gop.found_existing) {
1055 sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{1083 lazy_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1056 .type = switch (lazy.kind) {1084 .type = switch (lazy.kind) {
1057 .code => .FUNC,1085 .code => .FUNC,
1058 .const_data => .OBJECT,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}
10651093
1066pub fn getNavVAddr(1094pub fn getNavVAddr(
...@@ -1088,7 +1116,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In...@@ -1088,7 +1116,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
1088 reloc_info.addend,1116 reloc_info.addend,
1089 switch (elf.ehdrField(.machine)) {1117 switch (elf.ehdrField(.machine)) {
1090 else => unreachable,1118 else => unreachable,
1091 .X86_64 => .{ .x86_64 = switch (elf.identClass()) {1119 .X86_64 => .{ .X86_64 = switch (elf.identClass()) {
1092 .NONE, _ => unreachable,1120 .NONE, _ => unreachable,
1093 .@"32" => .@"32",1121 .@"32" => .@"32",
1094 .@"64" => .@"64",1122 .@"64" => .@"64",
...@@ -1107,7 +1135,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1107,7 +1135,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1107 entsize: std.elf.Word = 0,1135 entsize: std.elf.Word = 0,
1108}) !Symbol.Index {1136}) !Symbol.Index {
1109 const gpa = elf.base.comp.gpa;1137 const gpa = elf.base.comp.gpa;
1110 const target_endian = elf.endian();1138 const target_endian = elf.targetEndian();
1111 try elf.nodes.ensureUnusedCapacity(gpa, 1);1139 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1112 try elf.symtab.ensureUnusedCapacity(gpa, 1);1140 try elf.symtab.ensureUnusedCapacity(gpa, 1);
11131141
...@@ -1127,7 +1155,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1127,7 +1155,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1127 .size = opts.size,1155 .size = opts.size,
1128 .moved = true,1156 .moved = true,
1129 });1157 });
1130 const si = try elf.addSymbolAssumeCapacity();1158 const si = elf.addSymbolAssumeCapacity();
1131 elf.nodes.appendAssumeCapacity(.{ .section = si });1159 elf.nodes.appendAssumeCapacity(.{ .section = si });
1132 si.get(elf).ni = ni;1160 si.get(elf).ni = ni;
1133 try si.init(elf, .{1161 try si.init(elf, .{
...@@ -1160,7 +1188,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1160,7 +1188,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1160fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {1188fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
1161 const strtab_entry = try elf.string(.strtab, name);1189 const strtab_entry = try elf.string(.strtab, name);
1162 const shstrtab_entry = try elf.string(.shstrtab, name);1190 const shstrtab_entry = try elf.string(.shstrtab, name);
1163 const target_endian = elf.endian();1191 const target_endian = elf.targetEndian();
1164 switch (elf.shdrSlice()) {1192 switch (elf.shdrSlice()) {
1165 inline else => |shdr, class| {1193 inline else => |shdr, class| {
1166 const sym = @field(elf.symPtr(si), @tagName(class));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,7 +1201,7 @@ fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
1173}1201}
11741202
1175fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {1203fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
1176 const target_endian = elf.endian();1204 const target_endian = elf.targetEndian();
1177 switch (elf.shdrSlice()) {1205 switch (elf.shdrSlice()) {
1178 inline else => |shdr, class| {1206 inline else => |shdr, class| {
1179 const sym = @field(elf.symPtr(si), @tagName(class));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,7 +1212,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
1184}1212}
11851213
1186fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {1214fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
1187 const target_endian = elf.endian();1215 const target_endian = elf.targetEndian();
1188 const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[name: switch (elf.shdrSlice()) {1216 const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[name: switch (elf.shdrSlice()) {
1189 inline else => |shndx, class| {1217 inline else => |shndx, class| {
1190 const sym = @field(elf.symPtr(si), @tagName(class));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,7 +1291,8 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
1263 };1291 };
1264 if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return;1292 if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return;
12651293
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 const ni = ni: {1296 const ni = ni: {
1268 const sym = si.get(elf);1297 const sym = si.get(elf);
1269 switch (sym.ni) {1298 switch (sym.ni) {
...@@ -1275,7 +1304,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -1275,7 +1304,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
1275 .alignment = pt.navAlignment(nav_index).toStdMem(),1304 .alignment = pt.navAlignment(nav_index).toStdMem(),
1276 .moved = true,1305 .moved = true,
1277 });1306 });
1278 elf.nodes.appendAssumeCapacity(.{ .nav = nav_index });1307 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
1279 sym.ni = ni;1308 sym.ni = ni;
1280 switch (elf.symPtr(si)) {1309 switch (elf.symPtr(si)) {
1281 inline else => |sym_ptr, class| sym_ptr.shndx =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,28 +1318,24 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
1289 break :ni sym.ni;1318 break :ni sym.ni;
1290 };1319 };
12911320
1292 const size = size: {1321 var nw: MappedFile.Node.Writer = undefined;
1293 var nw: MappedFile.Node.Writer = undefined;1322 ni.writer(&elf.mf, gpa, &nw);
1294 ni.writer(&elf.mf, gpa, &nw);1323 defer nw.deinit();
1295 defer nw.deinit();1324 codegen.generateSymbol(
1296 codegen.generateSymbol(1325 &elf.base,
1297 &elf.base,1326 pt,
1298 pt,1327 zcu.navSrcLoc(nav_index),
1299 zcu.navSrcLoc(nav_index),1328 .fromInterned(nav_init),
1300 .fromInterned(nav_init),1329 &nw.interface,
1301 &nw.interface,1330 .{ .atom_index = @intFromEnum(si) },
1302 .{ .atom_index = @intFromEnum(si) },1331 ) catch |err| switch (err) {
1303 ) catch |err| switch (err) {1332 error.WriteFailed => return error.OutOfMemory,
1304 error.WriteFailed => return error.OutOfMemory,1333 else => |e| return e,
1305 else => |e| return e,
1306 };
1307 break :size nw.interface.end;
1308 };1334 };
13091335 const target_endian = elf.targetEndian();
1310 const target_endian = elf.endian();
1311 switch (elf.symPtr(si)) {1336 switch (elf.symPtr(si)) {
1312 inline else => |sym| sym.size =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 si.applyLocationRelocs(elf);1340 si.applyLocationRelocs(elf);
1316}1341}
...@@ -1326,7 +1351,7 @@ pub fn lowerUav(...@@ -1326,7 +1351,7 @@ pub fn lowerUav(
1326 const gpa = zcu.gpa;1351 const gpa = zcu.gpa;
13271352
1328 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);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 error.OutOfMemory => return error.OutOfMemory,1355 error.OutOfMemory => return error.OutOfMemory,
1331 else => |e| return .{ .fail = try Zcu.ErrorMsg.create(1356 else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
1332 gpa,1357 gpa,
...@@ -1335,11 +1360,12 @@ pub fn lowerUav(...@@ -1335,11 +1360,12 @@ pub fn lowerUav(
1335 .{@errorName(e)},1360 .{@errorName(e)},
1336 ) },1361 ) },
1337 };1362 };
1363 const si = umi.symbol(elf);
1338 if (switch (si.get(elf).ni) {1364 if (switch (si.get(elf).ni) {
1339 .none => true,1365 .none => true,
1340 else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt),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 if (gop.found_existing) {1369 if (gop.found_existing) {
1344 gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);1370 gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);
1345 } else {1371 } else {
...@@ -1347,7 +1373,7 @@ pub fn lowerUav(...@@ -1347,7 +1373,7 @@ pub fn lowerUav(
1347 .alignment = uav_align,1373 .alignment = uav_align,
1348 .src_loc = src_loc,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 return .{ .sym_index = @intFromEnum(si) };1379 return .{ .sym_index = @intFromEnum(si) };
...@@ -1384,7 +1410,8 @@ fn updateFuncInner(...@@ -1384,7 +1410,8 @@ fn updateFuncInner(
1384 const func = zcu.funcInfo(func_index);1410 const func = zcu.funcInfo(func_index);
1385 const nav = ip.getNav(func.owner_nav);1411 const nav = ip.getNav(func.owner_nav);
13861412
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 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });1415 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });
1389 const ni = ni: {1416 const ni = ni: {
1390 const sym = si.get(elf);1417 const sym = si.get(elf);
...@@ -1406,7 +1433,7 @@ fn updateFuncInner(...@@ -1406,7 +1433,7 @@ fn updateFuncInner(
1406 }.toStdMem(),1433 }.toStdMem(),
1407 .moved = true,1434 .moved = true,
1408 });1435 });
1409 elf.nodes.appendAssumeCapacity(.{ .nav = func.owner_nav });1436 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
1410 sym.ni = ni;1437 sym.ni = ni;
1411 switch (elf.symPtr(si)) {1438 switch (elf.symPtr(si)) {
1412 inline else => |sym_ptr, class| sym_ptr.shndx =1439 inline else => |sym_ptr, class| sym_ptr.shndx =
...@@ -1420,37 +1447,35 @@ fn updateFuncInner(...@@ -1420,37 +1447,35 @@ fn updateFuncInner(
1420 break :ni sym.ni;1447 break :ni sym.ni;
1421 };1448 };
14221449
1423 const size = size: {1450 var nw: MappedFile.Node.Writer = undefined;
1424 var nw: MappedFile.Node.Writer = undefined;1451 ni.writer(&elf.mf, gpa, &nw);
1425 ni.writer(&elf.mf, gpa, &nw);1452 defer nw.deinit();
1426 defer nw.deinit();1453 codegen.emitFunction(
1427 codegen.emitFunction(1454 &elf.base,
1428 &elf.base,1455 pt,
1429 pt,1456 zcu.navSrcLoc(func.owner_nav),
1430 zcu.navSrcLoc(func.owner_nav),1457 func_index,
1431 func_index,1458 @intFromEnum(si),
1432 @intFromEnum(si),1459 mir,
1433 mir,1460 &nw.interface,
1434 &nw.interface,1461 .none,
1435 .none,1462 ) catch |err| switch (err) {
1436 ) catch |err| switch (err) {1463 error.WriteFailed => return nw.err.?,
1437 error.WriteFailed => return nw.err.?,1464 else => |e| return e,
1438 else => |e| return e,
1439 };
1440 break :size nw.interface.end;
1441 };1465 };
14421466 const target_endian = elf.targetEndian();
1443 const target_endian = elf.endian();
1444 switch (elf.symPtr(si)) {1467 switch (elf.symPtr(si)) {
1445 inline else => |sym| sym.size =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 si.applyLocationRelocs(elf);1471 si.applyLocationRelocs(elf);
1449}1472}
14501473
1451pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {1474pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
1452 const si = elf.lazy.getPtr(.const_data).map.get(.anyerror_type) orelse return;1475 elf.flushLazy(pt, .{
1453 elf.flushLazy(pt, .{ .kind = .const_data, .ty = .anyerror_type }, si) catch |err| switch (err) {1476 .kind = .const_data,
1477 .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),
1478 }) catch |err| switch (err) {
1454 error.OutOfMemory => return error.OutOfMemory,1479 error.OutOfMemory => return error.OutOfMemory,
1455 error.CodegenFail => return error.LinkFailure,1480 error.CodegenFail => return error.LinkFailure,
1456 else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}),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,14 +1497,13 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1472 const comp = elf.base.comp;1497 const comp = elf.base.comp;
1473 task: {1498 task: {
1474 while (elf.pending_uavs.pop()) |pending_uav| {1499 while (elf.pending_uavs.pop()) |pending_uav| {
1475 const sub_prog_node =1500 const sub_prog_node = elf.idleProgNode(
1476 elf.idleProgNode(1501 tid,
1477 tid,1502 comp.link_const_prog_node,
1478 comp.link_uav_prog_node,1503 .{ .uav = pending_uav.key },
1479 .{ .uav = pending_uav.key },1504 );
1480 );
1481 defer sub_prog_node.end();1505 defer sub_prog_node.end();
1482 break :task elf.flushUav(1506 elf.flushUav(
1483 .{ .zcu = elf.base.comp.zcu.?, .tid = tid },1507 .{ .zcu = elf.base.comp.zcu.?, .tid = tid },
1484 pending_uav.key,1508 pending_uav.key,
1485 pending_uav.value.alignment,1509 pending_uav.value.alignment,
...@@ -1491,37 +1515,34 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {...@@ -1491,37 +1515,34 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1491 .{e},1515 .{e},
1492 ),1516 ),
1493 };1517 };
1518 break :task;
1494 }1519 }
1495 var lazy_it = elf.lazy.iterator();1520 var lazy_it = elf.lazy.iterator();
1496 while (lazy_it.next()) |lazy| for (1521 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {
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;
1501 const pt: Zcu.PerThread = .{ .zcu = elf.base.comp.zcu.?, .tid = tid };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 .code => "code",1526 .code => "code",
1504 .const_data => "data",1527 .const_data => "data",
1505 };1528 };
1506 var name: [std.Progress.Node.max_name_len]u8 = undefined;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 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{1531 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
1509 kind,1532 kind,
1510 Type.fromInterned(ty).fmt(pt),1533 Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt),
1511 }) catch &name,1534 }) catch &name,
1512 0,1535 0,
1513 );1536 );
1514 defer sub_prog_node.end();1537 defer sub_prog_node.end();
1515 break :task elf.flushLazy(pt, .{1538 elf.flushLazy(pt, lmr) catch |err| switch (err) {
1516 .kind = lazy.key,
1517 .ty = ty,
1518 }, si) catch |err| switch (err) {
1519 error.OutOfMemory => return error.OutOfMemory,1539 error.OutOfMemory => return error.OutOfMemory,
1520 else => |e| return elf.base.comp.link_diags.fail(1540 else => |e| return elf.base.comp.link_diags.fail(
1521 "linker failed to lower lazy {s}: {t}",1541 "linker failed to lower lazy {s}: {t}",
1522 .{ kind, e },1542 .{ kind, e },
1523 ),1543 ),
1524 };1544 };
1545 break :task;
1525 };1546 };
1526 while (elf.mf.updates.pop()) |ni| {1547 while (elf.mf.updates.pop()) |ni| {
1527 const clean_moved = ni.cleanMoved(&elf.mf);1548 const clean_moved = ni.cleanMoved(&elf.mf);
...@@ -1551,12 +1572,12 @@ fn idleProgNode(...@@ -1551,12 +1572,12 @@ fn idleProgNode(
1551 return prog_node.start(name: switch (node) {1572 return prog_node.start(name: switch (node) {
1552 else => |tag| @tagName(tag),1573 else => |tag| @tagName(tag),
1553 .section => |si| elf.sectionName(si),1574 .section => |si| elf.sectionName(si),
1554 .nav => |nav| {1575 .nav => |nmi| {
1555 const ip = &elf.base.comp.zcu.?.intern_pool;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}", .{1579 .uav => |umi| std.fmt.bufPrint(&name, "{f}", .{
1559 Value.fromInterned(uav).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),1580 Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
1560 }) catch &name,1581 }) catch &name,
1561 }, 0);1582 }, 0);
1562}1583}
...@@ -1564,14 +1585,15 @@ fn idleProgNode(...@@ -1564,14 +1585,15 @@ fn idleProgNode(
1564fn flushUav(1585fn flushUav(
1565 elf: *Elf,1586 elf: *Elf,
1566 pt: Zcu.PerThread,1587 pt: Zcu.PerThread,
1567 uav_val: InternPool.Index,1588 umi: Node.UavMapIndex,
1568 uav_align: InternPool.Alignment,1589 uav_align: InternPool.Alignment,
1569 src_loc: Zcu.LazySrcLoc,1590 src_loc: Zcu.LazySrcLoc,
1570) !void {1591) !void {
1571 const zcu = pt.zcu;1592 const zcu = pt.zcu;
1572 const gpa = zcu.gpa;1593 const gpa = zcu.gpa;
15731594
1574 const si = try elf.uavSymbol(uav_val);1595 const uav_val = umi.uavValue(elf);
1596 const si = umi.symbol(elf);
1575 const ni = ni: {1597 const ni = ni: {
1576 const sym = si.get(elf);1598 const sym = si.get(elf);
1577 switch (sym.ni) {1599 switch (sym.ni) {
...@@ -1581,7 +1603,7 @@ fn flushUav(...@@ -1581,7 +1603,7 @@ fn flushUav(
1581 .alignment = uav_align.toStdMem(),1603 .alignment = uav_align.toStdMem(),
1582 .moved = true,1604 .moved = true,
1583 });1605 });
1584 elf.nodes.appendAssumeCapacity(.{ .uav = uav_val });1606 elf.nodes.appendAssumeCapacity(.{ .uav = umi });
1585 sym.ni = ni;1607 sym.ni = ni;
1586 switch (elf.symPtr(si)) {1608 switch (elf.symPtr(si)) {
1587 inline else => |sym_ptr, class| sym_ptr.shndx =1609 inline else => |sym_ptr, class| sym_ptr.shndx =
...@@ -1598,36 +1620,34 @@ fn flushUav(...@@ -1598,36 +1620,34 @@ fn flushUav(
1598 break :ni sym.ni;1620 break :ni sym.ni;
1599 };1621 };
16001622
1601 const size = size: {1623 var nw: MappedFile.Node.Writer = undefined;
1602 var nw: MappedFile.Node.Writer = undefined;1624 ni.writer(&elf.mf, gpa, &nw);
1603 ni.writer(&elf.mf, gpa, &nw);1625 defer nw.deinit();
1604 defer nw.deinit();1626 codegen.generateSymbol(
1605 codegen.generateSymbol(1627 &elf.base,
1606 &elf.base,1628 pt,
1607 pt,1629 src_loc,
1608 src_loc,1630 .fromInterned(uav_val),
1609 .fromInterned(uav_val),1631 &nw.interface,
1610 &nw.interface,1632 .{ .atom_index = @intFromEnum(si) },
1611 .{ .atom_index = @intFromEnum(si) },1633 ) catch |err| switch (err) {
1612 ) catch |err| switch (err) {1634 error.WriteFailed => return error.OutOfMemory,
1613 error.WriteFailed => return error.OutOfMemory,1635 else => |e| return e,
1614 else => |e| return e,
1615 };
1616 break :size nw.interface.end;
1617 };1636 };
16181637 const target_endian = elf.targetEndian();
1619 const target_endian = elf.endian();
1620 switch (elf.symPtr(si)) {1638 switch (elf.symPtr(si)) {
1621 inline else => |sym| sym.size =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 si.applyLocationRelocs(elf);1642 si.applyLocationRelocs(elf);
1625}1643}
16261644
1627fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbol.Index) !void {1645fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
1628 const zcu = pt.zcu;1646 const zcu = pt.zcu;
1629 const gpa = zcu.gpa;1647 const gpa = zcu.gpa;
16301648
1649 const lazy = lmr.lazySymbol(elf);
1650 const si = lmr.symbol(elf);
1631 const ni = ni: {1651 const ni = ni: {
1632 const sym = si.get(elf);1652 const sym = si.get(elf);
1633 switch (sym.ni) {1653 switch (sym.ni) {
...@@ -1639,8 +1659,8 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo...@@ -1639,8 +1659,8 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo
1639 };1659 };
1640 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true });1660 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true });
1641 elf.nodes.appendAssumeCapacity(switch (lazy.kind) {1661 elf.nodes.appendAssumeCapacity(switch (lazy.kind) {
1642 .code => .{ .lazy_code = lazy.ty },1662 .code => .{ .lazy_code = @enumFromInt(lmr.index) },
1643 .const_data => .{ .lazy_const_data = lazy.ty },1663 .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) },
1644 });1664 });
1645 sym.ni = ni;1665 sym.ni = ni;
1646 switch (elf.symPtr(si)) {1666 switch (elf.symPtr(si)) {
...@@ -1655,34 +1675,30 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo...@@ -1655,34 +1675,30 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo
1655 break :ni sym.ni;1675 break :ni sym.ni;
1656 };1676 };
16571677
1658 const size = size: {1678 var required_alignment: InternPool.Alignment = .none;
1659 var required_alignment: InternPool.Alignment = .none;1679 var nw: MappedFile.Node.Writer = undefined;
1660 var nw: MappedFile.Node.Writer = undefined;1680 ni.writer(&elf.mf, gpa, &nw);
1661 ni.writer(&elf.mf, gpa, &nw);1681 defer nw.deinit();
1662 defer nw.deinit();1682 try codegen.generateLazySymbol(
1663 try codegen.generateLazySymbol(1683 &elf.base,
1664 &elf.base,1684 pt,
1665 pt,1685 Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded,
1666 Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded,1686 lazy,
1667 lazy,1687 &required_alignment,
1668 &required_alignment,1688 &nw.interface,
1669 &nw.interface,1689 .none,
1670 .none,1690 .{ .atom_index = @intFromEnum(si) },
1671 .{ .atom_index = @intFromEnum(si) },1691 );
1672 );1692 const target_endian = elf.targetEndian();
1673 break :size nw.interface.end;
1674 };
1675
1676 const target_endian = elf.endian();
1677 switch (elf.symPtr(si)) {1693 switch (elf.symPtr(si)) {
1678 inline else => |sym| sym.size =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 si.applyLocationRelocs(elf);1697 si.applyLocationRelocs(elf);
1682}1698}
16831699
1684fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {1700fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
1685 const target_endian = elf.endian();1701 const target_endian = elf.targetEndian();
1686 const file_offset = ni.fileLocation(&elf.mf, false).offset;1702 const file_offset = ni.fileLocation(&elf.mf, false).offset;
1687 const node = elf.getNode(ni);1703 const node = elf.getNode(ni);
1688 switch (node) {1704 switch (node) {
...@@ -1738,11 +1754,8 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -1738,11 +1754,8 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
1738 .nav, .uav, .lazy_code, .lazy_const_data => {1754 .nav, .uav, .lazy_code, .lazy_const_data => {
1739 const si = switch (node) {1755 const si = switch (node) {
1740 else => unreachable,1756 else => unreachable,
1741 .nav => |nav| elf.navs.get(nav),1757 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
1742 .uav => |uav| elf.uavs.get(uav),1758 };
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 }.?;
1746 switch (elf.shdrSlice()) {1759 switch (elf.shdrSlice()) {
1747 inline else => |shdr, class| {1760 inline else => |shdr, class| {
1748 const sym = @field(elf.symPtr(si), @tagName(class));1761 const sym = @field(elf.symPtr(si), @tagName(class));
...@@ -1773,7 +1786,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -1773,7 +1786,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
1773}1786}
17741787
1775fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {1788fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
1776 const target_endian = elf.endian();1789 const target_endian = elf.targetEndian();
1777 _, const size = ni.location(&elf.mf).resolve(&elf.mf);1790 _, const size = ni.location(&elf.mf).resolve(&elf.mf);
1778 const node = elf.getNode(ni);1791 const node = elf.getNode(ni);
1779 switch (node) {1792 switch (node) {
...@@ -1957,65 +1970,74 @@ pub fn printNode(...@@ -1957,65 +1970,74 @@ pub fn printNode(
1957 indent: usize,1970 indent: usize,
1958) !void {1971) !void {
1959 const node = elf.getNode(ni);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 try w.splatByteAll(' ', indent);1973 try w.splatByteAll(' ', indent);
1963 try w.writeAll(@tagName(node));1974 try w.writeAll(@tagName(node));
1964 switch (node) {1975 switch (node) {
1965 else => {},1976 else => {},
1966 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),1977 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),
1967 .nav => |nav_index| {1978 .nav => |nmi| {
1968 const zcu = elf.base.comp.zcu.?;1979 const zcu = elf.base.comp.zcu.?;
1969 const ip = &zcu.intern_pool;1980 const ip = &zcu.intern_pool;
1970 const nav = ip.getNav(nav_index);1981 const nav = ip.getNav(nmi.navIndex(elf));
1971 try w.print("({f}, {f})", .{1982 try w.print("({f}, {f})", .{
1972 Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }),1983 Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }),
1973 nav.fqn.fmt(ip),1984 nav.fqn.fmt(ip),
1974 });1985 });
1975 },1986 },
1976 .uav => |uav| {1987 .uav => |umi| {
1977 const zcu = elf.base.comp.zcu.?;1988 const zcu = elf.base.comp.zcu.?;
1978 const val: Value = .fromInterned(uav);1989 const val: Value = .fromInterned(umi.uavValue(elf));
1979 try w.print("({f}, {f})", .{1990 try w.print("({f}, {f})", .{
1980 val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }),1991 val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }),
1981 val.fmtValue(.{ .zcu = zcu, .tid = tid }),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", .{2002 {
1986 @intFromEnum(ni),2003 const mf_node = &elf.mf.nodes.items[@intFromEnum(ni)];
1987 off,2004 const off, const size = mf_node.location().resolve(&elf.mf);
1988 size,2005 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{
1989 mf_node.flags.alignment.toByteUnits(),2006 @intFromEnum(ni),
1990 if (mf_node.flags.fixed) " fixed" else "",2007 off,
1991 if (mf_node.flags.moved) " moved" else "",2008 size,
1992 if (mf_node.flags.resized) " resized" else "",2009 mf_node.flags.alignment.toByteUnits(),
1993 if (mf_node.flags.has_content) " has_content" else "",2010 if (mf_node.flags.fixed) " fixed" else "",
1994 });2011 if (mf_node.flags.moved) " moved" else "",
1995 var child_ni = mf_node.first;2012 if (mf_node.flags.resized) " resized" else "",
1996 switch (child_ni) {2013 if (mf_node.flags.has_content) " has_content" else "",
1997 .none => {2014 });
1998 const file_loc = ni.fileLocation(&elf.mf, false);2015 }
1999 if (file_loc.size == 0) return;2016 var leaf = true;
2000 var address = file_loc.offset;2017 var child_it = ni.children(&elf.mf);
2001 const line_len = 0x10;2018 while (child_it.next()) |child_ni| {
2002 var line_it = std.mem.window(2019 leaf = false;
2003 u8,2020 try elf.printNode(tid, w, child_ni, indent + 1);
2004 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],2021 }
2005 line_len,2022 if (leaf) {
2006 line_len,2023 const file_loc = ni.fileLocation(&elf.mf, false);
2007 );2024 if (file_loc.size == 0) return;
2008 while (line_it.next()) |line_bytes| : (address += line_len) {2025 var address = file_loc.offset;
2009 try w.splatByteAll(' ', indent + 1);2026 const line_len = 0x10;
2010 try w.print("{x:0>8}", .{address});2027 var line_it = std.mem.window(
2011 for (line_bytes) |byte| try w.print(" {x:0>2}", .{byte});2028 u8,
2012 try w.writeByte('\n');2029 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
2013 }2030 line_len,
2014 },2031 line_len,
2015 else => while (child_ni != .none) {2032 );
2016 try elf.printNode(tid, w, child_ni, indent + 1);2033 while (line_it.next()) |line_bytes| : (address += line_len) {
2017 child_ni = elf.mf.nodes.items[@intFromEnum(child_ni)].next;2034 try w.splatByteAll(' ', indent + 1);
2018 },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}
20212043
src/link/MappedFile.zig+50-20
...@@ -34,17 +34,28 @@ pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile {...@@ -34,17 +34,28 @@ pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile {
34 .writers = .{},34 .writers = .{},
35 };35 };
36 errdefer mf.deinit(gpa);36 errdefer mf.deinit(gpa);
37 const size: u64, const blksize = if (is_windows)37 const size: u64, const block_size = stat: {
38 .{ try windows.GetFileSizeEx(file.handle), 1 }38 if (is_windows) {
39 else stat: {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 const stat = try std.posix.fstat(mf.file.handle);53 const stat = try std.posix.fstat(mf.file.handle);
41 if (!std.posix.S.ISREG(stat.mode)) return error.PathAlreadyExists;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 mf.flags = .{57 mf.flags = .{
45 .block_size = .fromByteUnits(58 .block_size = .fromByteUnits(std.math.ceilPowerOfTwoAssert(usize, block_size)),
46 std.math.ceilPowerOfTwoAssert(usize, @max(std.heap.pageSize(), blksize)),
47 ),
48 .copy_file_range_unsupported = false,59 .copy_file_range_unsupported = false,
49 .fallocate_insert_range_unsupported = false,60 .fallocate_insert_range_unsupported = false,
50 .fallocate_punch_hole_unsupported = false,61 .fallocate_punch_hole_unsupported = false,
...@@ -90,9 +101,11 @@ pub const Node = extern struct {...@@ -90,9 +101,11 @@ pub const Node = extern struct {
90 resized: bool,101 resized: bool,
91 /// Whether this node might contain non-zero bytes.102 /// Whether this node might contain non-zero bytes.
92 has_content: bool,103 has_content: bool,
104 /// Whether a moved event on this node bubbles down to children.
105 bubbles_moved: bool,
93 unused: @Type(.{ .int = .{106 unused: @Type(.{ .int = .{
94 .signedness = .unsigned,107 .signedness = .unsigned,
95 .bits = 32 - @bitSizeOf(std.mem.Alignment) - 5,108 .bits = 32 - @bitSizeOf(std.mem.Alignment) - 6,
96 } }) = 0,109 } }) = 0,
97 };110 };
98111
...@@ -136,6 +149,25 @@ pub const Node = extern struct {...@@ -136,6 +149,25 @@ pub const Node = extern struct {
136 return &mf.nodes.items[@intFromEnum(ni)];149 return &mf.nodes.items[@intFromEnum(ni)];
137 }150 }
138151
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 pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void {171 pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void {
140 var child_ni = ni.get(mf).last;172 var child_ni = ni.get(mf).last;
141 while (child_ni != .none) {173 while (child_ni != .none) {
...@@ -147,9 +179,10 @@ pub const Node = extern struct {...@@ -147,9 +179,10 @@ pub const Node = extern struct {
147 pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool {179 pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool {
148 var parent_ni = ni;180 var parent_ni = ni;
149 while (parent_ni != Node.Index.root) {181 while (parent_ni != Node.Index.root) {
150 const parent = parent_ni.get(mf);182 const parent_node = parent_ni.get(mf);
151 if (parent.flags.moved) return true;183 if (!parent_node.flags.bubbles_moved) break;
152 parent_ni = parent.parent;184 if (parent_node.flags.moved) return true;
185 parent_ni = parent_node.parent;
153 }186 }
154 return false;187 return false;
155 }188 }
...@@ -163,12 +196,7 @@ pub const Node = extern struct {...@@ -163,12 +196,7 @@ pub const Node = extern struct {
163 return node_moved.*;196 return node_moved.*;
164 }197 }
165 fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {198 fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
166 var parent_ni = ni;199 if (ni.hasMoved(mf)) return;
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 }
172 const node = ni.get(mf);200 const node = ni.get(mf);
173 node.flags.moved = true;201 node.flags.moved = true;
174 if (node.flags.resized) return;202 if (node.flags.resized) return;
...@@ -242,10 +270,10 @@ pub const Node = extern struct {...@@ -242,10 +270,10 @@ pub const Node = extern struct {
242 var offset, const size = ni.location(mf).resolve(mf);270 var offset, const size = ni.location(mf).resolve(mf);
243 var parent_ni = ni;271 var parent_ni = ni;
244 while (true) {272 while (true) {
245 const parent = parent_ni.get(mf);273 const parent_node = parent_ni.get(mf);
246 if (set_has_content) parent.flags.has_content = true;274 if (set_has_content) parent_node.flags.has_content = true;
247 if (parent_ni == .none) break;275 if (parent_ni == .none) break;
248 parent_ni = parent.parent;276 parent_ni = parent_node.parent;
249 offset += parent_ni.location(mf).resolve(mf)[0];277 offset += parent_ni.location(mf).resolve(mf)[0];
250 }278 }
251 return .{ .offset = offset, .size = size };279 return .{ .offset = offset, .size = size };
...@@ -449,6 +477,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {...@@ -449,6 +477,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
449 .moved = true,477 .moved = true,
450 .resized = true,478 .resized = true,
451 .has_content = false,479 .has_content = false,
480 .bubbles_moved = opts.add_node.bubbles_moved,
452 },481 },
453 .location_payload = location_payload,482 .location_payload = location_payload,
454 };483 };
...@@ -471,6 +500,7 @@ pub const AddNodeOptions = struct {...@@ -471,6 +500,7 @@ pub const AddNodeOptions = struct {
471 fixed: bool = false,500 fixed: bool = false,
472 moved: bool = false,501 moved: bool = false,
473 resized: bool = false,502 resized: bool = false,
503 bubbles_moved: bool = true,
474};504};
475505
476pub fn addOnlyChildNode(506pub fn addOnlyChildNode(
src/target.zig+1-1
...@@ -233,7 +233,7 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {...@@ -233,7 +233,7 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
233233
234pub fn hasNewLinkerSupport(ofmt: std.Target.ObjectFormat, backend: std.builtin.CompilerBackend) bool {234pub fn hasNewLinkerSupport(ofmt: std.Target.ObjectFormat, backend: std.builtin.CompilerBackend) bool {
235 return switch (ofmt) {235 return switch (ofmt) {
236 .elf => switch (backend) {236 .elf, .coff => switch (backend) {
237 .stage2_x86_64 => true,237 .stage2_x86_64 => true,
238 else => false,238 else => false,
239 },239 },
test/behavior/cast.zig-2
...@@ -1650,7 +1650,6 @@ test "coerce between pointers of compatible differently-named floats" {...@@ -1650,7 +1650,6 @@ test "coerce between pointers of compatible differently-named floats" {
1650 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;1650 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;
1651 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1651 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1652 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1653 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16551654
1656 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {1655 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
...@@ -2883,7 +2882,6 @@ test "@intFromFloat vector boundary cases" {...@@ -2883,7 +2882,6 @@ test "@intFromFloat vector boundary cases" {
2883 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;2882 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2884 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2883 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2885 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;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;
28872885
2888 const S = struct {2886 const S = struct {
2889 fn case(comptime I: type, unshifted_inputs: [2]f32, expected: [2]I) !void {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,7 +43,6 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion) void {
43}43}
4444
45test "export function alias" {45test "export function alias" {
46 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;46 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4847
49 _ = struct {48 _ = struct {
test/behavior/extern.zig-2
...@@ -16,7 +16,6 @@ export var a_mystery_symbol: i32 = 1234;...@@ -16,7 +16,6 @@ export var a_mystery_symbol: i32 = 1234;
1616
17test "function extern symbol" {17test "function extern symbol" {
18 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;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 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2120
22 const a = @extern(*const fn () callconv(.c) i32, .{ .name = "a_mystery_function" });21 const a = @extern(*const fn () callconv(.c) i32, .{ .name = "a_mystery_function" });
...@@ -29,7 +28,6 @@ export fn a_mystery_function() i32 {...@@ -29,7 +28,6 @@ export fn a_mystery_function() i32 {
2928
30test "function extern symbol matches extern decl" {29test "function extern symbol matches extern decl" {
31 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;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 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;31 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3432
35 const S = struct {33 const S = struct {
test/behavior/floatop.zig-17
...@@ -158,7 +158,6 @@ test "cmp f80/c_longdouble" {...@@ -158,7 +158,6 @@ test "cmp f80/c_longdouble" {
158 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;158 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
160 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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;
162161
163 try testCmp(f80);162 try testCmp(f80);
164 try comptime testCmp(f80);163 try comptime testCmp(f80);
...@@ -283,7 +282,6 @@ test "vector cmp f80/c_longdouble" {...@@ -283,7 +282,6 @@ test "vector cmp f80/c_longdouble" {
283 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;282 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
284 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;283 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
285 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;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;
287285
288 try testCmpVector(f80);286 try testCmpVector(f80);
289 try comptime testCmpVector(f80);287 try comptime testCmpVector(f80);
...@@ -396,7 +394,6 @@ test "@sqrt f80/f128/c_longdouble" {...@@ -396,7 +394,6 @@ test "@sqrt f80/f128/c_longdouble" {
396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO394 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
397 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;395 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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;
400397
401 if (builtin.os.tag == .freebsd) {398 if (builtin.os.tag == .freebsd) {
402 // TODO https://github.com/ziglang/zig/issues/10875399 // TODO https://github.com/ziglang/zig/issues/10875
...@@ -526,7 +523,6 @@ test "@sin f80/f128/c_longdouble" {...@@ -526,7 +523,6 @@ test "@sin f80/f128/c_longdouble" {
526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO523 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
527 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;524 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
528 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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;
530526
531 try testSin(f80);527 try testSin(f80);
532 comptime try testSin(f80);528 comptime try testSin(f80);
...@@ -596,7 +592,6 @@ test "@cos f80/f128/c_longdouble" {...@@ -596,7 +592,6 @@ test "@cos f80/f128/c_longdouble" {
596 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO592 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
597 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;593 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
598 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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;
600595
601 try testCos(f80);596 try testCos(f80);
602 try comptime testCos(f80);597 try comptime testCos(f80);
...@@ -666,7 +661,6 @@ test "@tan f80/f128/c_longdouble" {...@@ -666,7 +661,6 @@ test "@tan f80/f128/c_longdouble" {
666 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO661 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
667 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;662 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
668 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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;
670664
671 try testTan(f80);665 try testTan(f80);
672 try comptime testTan(f80);666 try comptime testTan(f80);
...@@ -736,7 +730,6 @@ test "@exp f80/f128/c_longdouble" {...@@ -736,7 +730,6 @@ test "@exp f80/f128/c_longdouble" {
736 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO730 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
737 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;731 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
738 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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;
740733
741 try testExp(f80);734 try testExp(f80);
742 try comptime testExp(f80);735 try comptime testExp(f80);
...@@ -810,7 +803,6 @@ test "@exp2 f80/f128/c_longdouble" {...@@ -810,7 +803,6 @@ test "@exp2 f80/f128/c_longdouble" {
810 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO803 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
811 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;804 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
812 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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;
814806
815 try testExp2(f80);807 try testExp2(f80);
816 try comptime testExp2(f80);808 try comptime testExp2(f80);
...@@ -879,7 +871,6 @@ test "@log f80/f128/c_longdouble" {...@@ -879,7 +871,6 @@ test "@log f80/f128/c_longdouble" {
879 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO871 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
880 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;872 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
881 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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;
883874
884 try testLog(f80);875 try testLog(f80);
885 try comptime testLog(f80);876 try comptime testLog(f80);
...@@ -946,7 +937,6 @@ test "@log2 f80/f128/c_longdouble" {...@@ -946,7 +937,6 @@ test "@log2 f80/f128/c_longdouble" {
946 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO937 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
947 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;938 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
948 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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;
950940
951 try testLog2(f80);941 try testLog2(f80);
952 try comptime testLog2(f80);942 try comptime testLog2(f80);
...@@ -1019,7 +1009,6 @@ test "@log10 f80/f128/c_longdouble" {...@@ -1019,7 +1009,6 @@ test "@log10 f80/f128/c_longdouble" {
1019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1009 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1020 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1010 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1021 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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;
10231012
1024 try testLog10(f80);1013 try testLog10(f80);
1025 try comptime testLog10(f80);1014 try comptime testLog10(f80);
...@@ -1086,7 +1075,6 @@ test "@abs f80/f128/c_longdouble" {...@@ -1086,7 +1075,6 @@ test "@abs f80/f128/c_longdouble" {
1086 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1075 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1087 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1076 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1088 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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;
10901078
1091 try testFabs(f80);1079 try testFabs(f80);
1092 try comptime testFabs(f80);1080 try comptime testFabs(f80);
...@@ -1204,7 +1192,6 @@ test "@floor f80/f128/c_longdouble" {...@@ -1204,7 +1192,6 @@ test "@floor f80/f128/c_longdouble" {
1204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1205 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;1193 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
1206 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1194 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 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1195 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1209 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1196 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12101197
...@@ -1295,7 +1282,6 @@ test "@ceil f80/f128/c_longdouble" {...@@ -1295,7 +1282,6 @@ test "@ceil f80/f128/c_longdouble" {
1295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1282 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1296 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;1283 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
1297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1284 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 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1285 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1300 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1286 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13011287
...@@ -1388,7 +1374,6 @@ test "@trunc f80/f128/c_longdouble" {...@@ -1388,7 +1374,6 @@ test "@trunc f80/f128/c_longdouble" {
1388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1374 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1389 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1375 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1390 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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;
13921377
1393 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {1378 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
1394 // https://github.com/ziglang/zig/issues/126021379 // https://github.com/ziglang/zig/issues/12602
...@@ -1485,7 +1470,6 @@ test "neg f80/f128/c_longdouble" {...@@ -1485,7 +1470,6 @@ test "neg f80/f128/c_longdouble" {
1485 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1470 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1486 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;1471 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1487 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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;
14891473
1490 try testNeg(f80);1474 try testNeg(f80);
1491 try comptime testNeg(f80);1475 try comptime testNeg(f80);
...@@ -1741,7 +1725,6 @@ test "comptime calls are only memoized when float arguments are bit-for-bit equa...@@ -1741,7 +1725,6 @@ test "comptime calls are only memoized when float arguments are bit-for-bit equa
1741test "result location forwarded through unary float builtins" {1725test "result location forwarded through unary float builtins" {
1742 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1726 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1743 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1727 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 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1728 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1746 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1729 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
17471730
test/behavior/import_c_keywords.zig-1
...@@ -31,7 +31,6 @@ test "import c keywords" {...@@ -31,7 +31,6 @@ test "import c keywords" {
31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;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 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;34 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3635
37 try std.testing.expect(int == .c_keyword_variable);36 try std.testing.expect(int == .c_keyword_variable);
test/behavior/math.zig+6-4
...@@ -1416,7 +1416,6 @@ test "remainder division" {...@@ -1416,7 +1416,6 @@ test "remainder division" {
1416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;1419 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
1421 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1420 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14221421
...@@ -1425,6 +1424,8 @@ test "remainder division" {...@@ -1425,6 +1424,8 @@ test "remainder division" {
1425 return error.SkipZigTest;1424 return error.SkipZigTest;
1426 }1425 }
14271426
1427 if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
1428
1428 try comptime remdiv(f16);1429 try comptime remdiv(f16);
1429 try comptime remdiv(f32);1430 try comptime remdiv(f32);
1430 try comptime remdiv(f64);1431 try comptime remdiv(f64);
...@@ -1496,9 +1497,10 @@ test "float modulo division using @mod" {...@@ -1496,9 +1497,10 @@ test "float modulo division using @mod" {
1496 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1497 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1498 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1500 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15011501
1502 if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
1503
1502 try comptime fmod(f16);1504 try comptime fmod(f16);
1503 try comptime fmod(f32);1505 try comptime fmod(f32);
1504 try comptime fmod(f64);1506 try comptime fmod(f64);
...@@ -1686,7 +1688,6 @@ test "signed zeros are represented properly" {...@@ -1686,7 +1688,6 @@ test "signed zeros are represented properly" {
1686 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1688 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1687 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1689 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1688 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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;
16901691
1691 const S = struct {1692 const S = struct {
1692 fn doTheTest() !void {1693 fn doTheTest() !void {
...@@ -1824,7 +1825,8 @@ test "float divide by zero" {...@@ -1824,7 +1825,8 @@ test "float divide by zero" {
1824 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1825 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1825 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1826 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1826 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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;
18281830
1829 const S = struct {1831 const S = struct {
1830 fn doTheTest(comptime F: type, zero: F, one: F) !void {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,7 +14,6 @@ test "call extern function defined with conflicting type" {
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;17 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1918
20 @import("conflicting_externs/a.zig").issue529(null);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,7 +5255,8 @@ inline fn mod(comptime Type: type, lhs: Type, rhs: Type) Type {
5255 return @mod(lhs, rhs);5255 return @mod(lhs, rhs);
5256}5256}
5257test mod {5257test 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 const test_mod = binary(mod, .{});5260 const test_mod = binary(mod, .{});
5260 try test_mod.testInts();5261 try test_mod.testInts();
5261 try test_mod.testIntVectors();5262 try test_mod.testIntVectors();
test/incremental/add_decl+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4//#target=wasm32-wasi-selfhosted5//#target=wasm32-wasi-selfhosted
test/incremental/add_decl_namespaced+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4//#target=wasm32-wasi-selfhosted5//#target=wasm32-wasi-selfhosted
test/incremental/analysis_error_and_syntax_error+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/bad_import+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/change_embed_file+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/change_enum_tag_type+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/change_exports+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
45
test/incremental/change_fn_type+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#update=initial version5#update=initial version
test/incremental/change_generic_line_number+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=wasm32-wasi-selfhosted3#target=wasm32-wasi-selfhosted
3#update=initial version4#update=initial version
4#file=main.zig5#file=main.zig
test/incremental/change_line_number+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=wasm32-wasi-selfhosted3#target=wasm32-wasi-selfhosted
3#update=initial version4#update=initial version
4#file=main.zig5#file=main.zig
test/incremental/change_module+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/change_panic_handler+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#update=initial version5#update=initial version
test/incremental/change_panic_handler_explicit+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#update=initial version5#update=initial version
test/incremental/change_shift_op+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/change_struct_same_fields+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/change_zon_file+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4//#target=wasm32-wasi-selfhosted5//#target=wasm32-wasi-selfhosted
test/incremental/change_zon_file_no_result_type+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4//#target=wasm32-wasi-selfhosted5//#target=wasm32-wasi-selfhosted
test/incremental/compile_error_then_log+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/compile_log+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/delete_comptime_decls+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/dependency_on_type_of_inferred_global+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/fix_astgen_failure+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/function_becomes_inline+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#update=non-inline version5#update=non-inline version
test/incremental/hello+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/make_decl_pub+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/modify_inline_fn+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/move_src+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/no_change_preserves_tag_names+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4//#target=wasm32-wasi-selfhosted5//#target=wasm32-wasi-selfhosted
test/incremental/recursive_function_becomes_non_recursive+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/remove_enum_field+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/remove_invalid_union_backing_enum+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/temporary_parse_error+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/type_becomes_comptime_only+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted
test/incremental/unreferenced_error+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
2#target=x86_64-linux-cbe3#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe4#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted5#target=wasm32-wasi-selfhosted