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 {
10821082 };
10831083}
10841084
1085pub fn toCoffMachine(target: *const Target) std.coff.MachineType {
1085pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
10861086 return switch (target.cpu.arch) {
10871087 .arm => .ARM,
10881088 .thumb => .ARMNT,
......@@ -1092,7 +1092,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.MachineType {
10921092 .riscv32 => .RISCV32,
10931093 .riscv64 => .RISCV64,
10941094 .x86 => .I386,
1095 .x86_64 => .X64,
1095 .x86_64 => .AMD64,
10961096
10971097 .amdgcn,
10981098 .arc,
lib/std/array_hash_map.zig+1-1
......@@ -50,7 +50,7 @@ pub fn eqlString(a: []const u8, b: []const u8) bool {
5050}
5151
5252pub 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));
5454}
5555
5656/// Deprecated in favor of `ArrayHashMapWithAllocator` (no code changes needed)
lib/std/coff.zig+771-432
......@@ -2,70 +2,9 @@ const std = @import("std.zig");
22const assert = std.debug.assert;
33const mem = std.mem;
44
5pub const CoffHeaderFlags = packed struct {
6 /// Image only, Windows CE, and Microsoft Windows NT and later.
7 /// This indicates that the file does not contain base relocations
8 /// and must therefore be loaded at its preferred base address.
9 /// If the base address is not available, the loader reports an error.
10 /// The default behavior of the linker is to strip base relocations
11 /// from executable (EXE) files.
12 RELOCS_STRIPPED: u1 = 0,
13
14 /// Image only. This indicates that the image file is valid and can be run.
15 /// If this flag is not set, it indicates a linker error.
16 EXECUTABLE_IMAGE: u1 = 0,
17
18 /// COFF line numbers have been removed. This flag is deprecated and should be zero.
19 LINE_NUMS_STRIPPED: u1 = 0,
20
21 /// COFF symbol table entries for local symbols have been removed.
22 /// This flag is deprecated and should be zero.
23 LOCAL_SYMS_STRIPPED: u1 = 0,
24
25 /// Obsolete. Aggressively trim working set.
26 /// This flag is deprecated for Windows 2000 and later and must be zero.
27 AGGRESSIVE_WS_TRIM: u1 = 0,
28
29 /// Application can handle > 2-GB addresses.
30 LARGE_ADDRESS_AWARE: u1 = 0,
31
32 /// This flag is reserved for future use.
33 RESERVED: u1 = 0,
34
35 /// Little endian: the least significant bit (LSB) precedes the
36 /// most significant bit (MSB) in memory. This flag is deprecated and should be zero.
37 BYTES_REVERSED_LO: u1 = 0,
38
39 /// Machine is based on a 32-bit-word architecture.
40 @"32BIT_MACHINE": u1 = 0,
41
42 /// Debugging information is removed from the image file.
43 DEBUG_STRIPPED: u1 = 0,
44
45 /// If the image is on removable media, fully load it and copy it to the swap file.
46 REMOVABLE_RUN_FROM_SWAP: u1 = 0,
47
48 /// If the image is on network media, fully load it and copy it to the swap file.
49 NET_RUN_FROM_SWAP: u1 = 0,
50
51 /// The image file is a system file, not a user program.
52 SYSTEM: u1 = 0,
53
54 /// The image file is a dynamic-link library (DLL).
55 /// Such files are considered executable files for almost all purposes,
56 /// although they cannot be directly run.
57 DLL: u1 = 0,
58
59 /// The file should be run only on a uniprocessor machine.
60 UP_SYSTEM_ONLY: u1 = 0,
61
62 /// Big endian: the MSB precedes the LSB in memory. This flag is deprecated and should be zero.
63 BYTES_REVERSED_HI: u1 = 0,
64};
65
66pub const CoffHeader = extern struct {
5pub const Header = extern struct {
676 /// The number that identifies the type of target machine.
68 machine: MachineType,
7 machine: IMAGE.FILE.MACHINE,
698
709 /// The number of sections. This indicates the size of the section table, which immediately follows the headers.
7110 number_of_sections: u16,
......@@ -88,49 +27,110 @@ pub const CoffHeader = extern struct {
8827 size_of_optional_header: u16,
8928
9029 /// 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 };
9292};
9393
9494// OptionalHeader.magic values
9595// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx
96pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
97pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
96pub const IMAGE_NT_OPTIONAL_HDR32_MAGIC = @intFromEnum(OptionalHeader.Magic.PE32);
97pub const IMAGE_NT_OPTIONAL_HDR64_MAGIC = @intFromEnum(OptionalHeader.Magic.@"PE32+");
9898
99pub const DllFlags = packed struct {
99pub const DllFlags = packed struct(u16) {
100100 _reserved_0: u5 = 0,
101101
102102 /// Image can handle a high entropy 64-bit virtual address space.
103 HIGH_ENTROPY_VA: u1 = 0,
103 HIGH_ENTROPY_VA: bool = false,
104104
105105 /// DLL can be relocated at load time.
106 DYNAMIC_BASE: u1 = 0,
106 DYNAMIC_BASE: bool = false,
107107
108108 /// Code Integrity checks are enforced.
109 FORCE_INTEGRITY: u1 = 0,
109 FORCE_INTEGRITY: bool = false,
110110
111111 /// Image is NX compatible.
112 NX_COMPAT: u1 = 0,
112 NX_COMPAT: bool = false,
113113
114114 /// Isolation aware, but do not isolate the image.
115 NO_ISOLATION: u1 = 0,
115 NO_ISOLATION: bool = false,
116116
117117 /// 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
120120 /// Do not bind the image.
121 NO_BIND: u1 = 0,
121 NO_BIND: bool = false,
122122
123123 /// Image must execute in an AppContainer.
124 APPCONTAINER: u1 = 0,
124 APPCONTAINER: bool = false,
125125
126126 /// A WDM driver.
127 WDM_DRIVER: u1 = 0,
127 WDM_DRIVER: bool = false,
128128
129129 /// Image supports Control Flow Guard.
130 GUARD_CF: u1 = 0,
130 GUARD_CF: bool = false,
131131
132132 /// Terminal Server aware.
133 TERMINAL_SERVER_AWARE: u1 = 0,
133 TERMINAL_SERVER_AWARE: bool = false,
134134};
135135
136136pub const Subsystem = enum(u16) {
......@@ -180,7 +180,7 @@ pub const Subsystem = enum(u16) {
180180};
181181
182182pub const OptionalHeader = extern struct {
183 magic: u16,
183 magic: OptionalHeader.Magic,
184184 major_linker_version: u8,
185185 minor_linker_version: u8,
186186 size_of_code: u32,
......@@ -188,71 +188,63 @@ pub const OptionalHeader = extern struct {
188188 size_of_uninitialized_data: u32,
189189 address_of_entry_point: u32,
190190 base_of_code: u32,
191};
192191
193pub const OptionalHeaderPE32 = extern struct {
194 magic: u16,
195 major_linker_version: u8,
196 minor_linker_version: u8,
197 size_of_code: u32,
198 size_of_initialized_data: u32,
199 size_of_uninitialized_data: u32,
200 address_of_entry_point: u32,
201 base_of_code: u32,
202 base_of_data: u32,
203 image_base: u32,
204 section_alignment: u32,
205 file_alignment: u32,
206 major_operating_system_version: u16,
207 minor_operating_system_version: u16,
208 major_image_version: u16,
209 minor_image_version: u16,
210 major_subsystem_version: u16,
211 minor_subsystem_version: u16,
212 win32_version_value: u32,
213 size_of_image: u32,
214 size_of_headers: u32,
215 checksum: u32,
216 subsystem: Subsystem,
217 dll_flags: DllFlags,
218 size_of_stack_reserve: u32,
219 size_of_stack_commit: u32,
220 size_of_heap_reserve: u32,
221 size_of_heap_commit: u32,
222 loader_flags: u32,
223 number_of_rva_and_sizes: u32,
224};
192 pub const Magic = enum(u16) {
193 PE32 = 0x10b,
194 @"PE32+" = 0x20b,
195 _,
196 };
225197
226pub const OptionalHeaderPE64 = extern struct {
227 magic: u16,
228 major_linker_version: u8,
229 minor_linker_version: u8,
230 size_of_code: u32,
231 size_of_initialized_data: u32,
232 size_of_uninitialized_data: u32,
233 address_of_entry_point: u32,
234 base_of_code: u32,
235 image_base: u64,
236 section_alignment: u32,
237 file_alignment: u32,
238 major_operating_system_version: u16,
239 minor_operating_system_version: u16,
240 major_image_version: u16,
241 minor_image_version: u16,
242 major_subsystem_version: u16,
243 minor_subsystem_version: u16,
244 win32_version_value: u32,
245 size_of_image: u32,
246 size_of_headers: u32,
247 checksum: u32,
248 subsystem: Subsystem,
249 dll_flags: DllFlags,
250 size_of_stack_reserve: u64,
251 size_of_stack_commit: u64,
252 size_of_heap_reserve: u64,
253 size_of_heap_commit: u64,
254 loader_flags: u32,
255 number_of_rva_and_sizes: u32,
198 pub const PE32 = extern struct {
199 standard: OptionalHeader,
200 base_of_data: u32,
201 image_base: u32,
202 section_alignment: u32,
203 file_alignment: u32,
204 major_operating_system_version: u16,
205 minor_operating_system_version: u16,
206 major_image_version: u16,
207 minor_image_version: u16,
208 major_subsystem_version: u16,
209 minor_subsystem_version: u16,
210 win32_version_value: u32,
211 size_of_image: u32,
212 size_of_headers: u32,
213 checksum: u32,
214 subsystem: Subsystem,
215 dll_flags: DllFlags,
216 size_of_stack_reserve: u32,
217 size_of_stack_commit: u32,
218 size_of_heap_reserve: u32,
219 size_of_heap_commit: u32,
220 loader_flags: u32,
221 number_of_rva_and_sizes: u32,
222 };
223
224 pub const @"PE32+" = extern struct {
225 standard: OptionalHeader,
226 image_base: u64,
227 section_alignment: u32,
228 file_alignment: u32,
229 major_operating_system_version: u16,
230 minor_operating_system_version: u16,
231 major_image_version: u16,
232 minor_image_version: u16,
233 major_subsystem_version: u16,
234 minor_subsystem_version: u16,
235 win32_version_value: u32,
236 size_of_image: u32,
237 size_of_headers: u32,
238 checksum: u32,
239 subsystem: Subsystem,
240 dll_flags: DllFlags,
241 size_of_stack_reserve: u64,
242 size_of_stack_commit: u64,
243 size_of_heap_reserve: u64,
244 size_of_heap_commit: u64,
245 loader_flags: u32,
246 number_of_rva_and_sizes: u32,
247 };
256248};
257249
258250pub const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
......@@ -319,7 +311,7 @@ pub const BaseRelocationDirectoryEntry = extern struct {
319311 block_size: u32,
320312};
321313
322pub const BaseRelocation = packed struct {
314pub const BaseRelocation = packed struct(u16) {
323315 /// 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.
324316 /// This offset specifies where the base relocation is to be applied.
325317 offset: u12,
......@@ -447,12 +439,12 @@ pub const ImportDirectoryEntry = extern struct {
447439};
448440
449441pub const ImportLookupEntry32 = struct {
450 pub const ByName = packed struct {
442 pub const ByName = packed struct(u32) {
451443 name_table_rva: u31,
452444 flag: u1 = 0,
453445 };
454446
455 pub const ByOrdinal = packed struct {
447 pub const ByOrdinal = packed struct(u32) {
456448 ordinal_number: u16,
457449 unused: u15 = 0,
458450 flag: u1 = 1,
......@@ -472,13 +464,13 @@ pub const ImportLookupEntry32 = struct {
472464};
473465
474466pub const ImportLookupEntry64 = struct {
475 pub const ByName = packed struct {
467 pub const ByName = packed struct(u64) {
476468 name_table_rva: u31,
477469 unused: u32 = 0,
478470 flag: u1 = 0,
479471 };
480472
481 pub const ByOrdinal = packed struct {
473 pub const ByOrdinal = packed struct(u64) {
482474 ordinal_number: u16,
483475 unused: u47 = 0,
484476 flag: u1 = 1,
......@@ -519,7 +511,7 @@ pub const SectionHeader = extern struct {
519511 pointer_to_linenumbers: u32,
520512 number_of_relocations: u16,
521513 number_of_linenumbers: u16,
522 flags: SectionHeaderFlags,
514 flags: SectionHeader.Flags,
523515
524516 pub fn getName(self: *align(1) const SectionHeader) ?[]const u8 {
525517 if (self.name[0] == '/') return null;
......@@ -546,109 +538,121 @@ pub const SectionHeader = extern struct {
546538 }
547539
548540 pub fn isCode(self: SectionHeader) bool {
549 return self.flags.CNT_CODE == 0b1;
541 return self.flags.CNT_CODE;
550542 }
551543
552544 pub fn isComdat(self: SectionHeader) bool {
553 return self.flags.LNK_COMDAT == 0b1;
545 return self.flags.LNK_COMDAT;
554546 }
555};
556547
557pub const SectionHeaderFlags = packed struct {
558 _reserved_0: u3 = 0,
548 pub const Flags = packed struct(u32) {
549 SCALE_INDEX: bool = false,
550
551 unused1: u2 = 0,
559552
560 /// The section should not be padded to the next boundary.
561 /// This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES.
562 /// This is valid only for object files.
563 TYPE_NO_PAD: u1 = 0,
553 /// The section should not be padded to the next boundary.
554 /// This flag is obsolete and is replaced by `.ALIGN = .@"1BYTES"`.
555 /// This is valid only for object files.
556 TYPE_NO_PAD: bool = false,
564557
565 _reserved_1: u1 = 0,
558 unused4: u1 = 0,
566559
567 /// The section contains executable code.
568 CNT_CODE: u1 = 0,
560 /// The section contains executable code.
561 CNT_CODE: bool = false,
569562
570 /// The section contains initialized data.
571 CNT_INITIALIZED_DATA: u1 = 0,
563 /// The section contains initialized data.
564 CNT_INITIALIZED_DATA: bool = false,
572565
573 /// The section contains uninitialized data.
574 CNT_UNINITIALIZED_DATA: u1 = 0,
566 /// The section contains uninitialized data.
567 CNT_UNINITIALIZED_DATA: bool = false,
575568
576 /// Reserved for future use.
577 LNK_OTHER: u1 = 0,
569 /// Reserved for future use.
570 LNK_OTHER: bool = false,
578571
579 /// The section contains comments or other information.
580 /// The .drectve section has this type.
581 /// This is valid for object files only.
582 LNK_INFO: u1 = 0,
572 /// The section contains comments or other information.
573 /// The .drectve section has this type.
574 /// This is valid for object files only.
575 LNK_INFO: bool = false,
583576
584 _reserved_2: u1 = 0,
577 unused10: u1 = 0,
585578
586 /// The section will not become part of the image.
587 /// This is valid only for object files.
588 LNK_REMOVE: u1 = 0,
579 /// The section will not become part of the image.
580 /// This is valid only for object files.
581 LNK_REMOVE: bool = false,
589582
590 /// The section contains COMDAT data.
591 /// For more information, see COMDAT Sections (Object Only).
592 /// This is valid only for object files.
593 LNK_COMDAT: u1 = 0,
583 /// The section contains COMDAT data.
584 /// For more information, see COMDAT Sections (Object Only).
585 /// This is valid only for object files.
586 LNK_COMDAT: bool = false,
594587
595 _reserved_3: u2 = 0,
588 unused13: u2 = 0,
596589
597 /// The section contains data referenced through the global pointer (GP).
598 GPREL: u1 = 0,
590 union14: packed union {
591 mask: u1,
592 /// The section contains data referenced through the global pointer (GP).
593 GPREL: bool,
594 MEM_FARDATA: bool,
595 } = .{ .mask = 0 },
599596
600 /// Reserved for future use.
601 MEM_PURGEABLE: u1 = 0,
597 unused15: u1 = 0,
602598
603 /// Reserved for future use.
604 MEM_16BIT: u1 = 0,
599 union16: packed union {
600 mask: u1,
601 MEM_PURGEABLE: bool,
602 MEM_16BIT: bool,
603 } = .{ .mask = 0 },
605604
606 /// Reserved for future use.
607 MEM_LOCKED: u1 = 0,
605 /// Reserved for future use.
606 MEM_LOCKED: bool = false,
608607
609 /// Reserved for future use.
610 MEM_PRELOAD: u1 = 0,
608 /// Reserved for future use.
609 MEM_PRELOAD: bool = false,
611610
612 /// Takes on multiple values according to flags:
613 /// pub const IMAGE_SCN_ALIGN_1BYTES: u32 = 0x100000;
614 /// pub const IMAGE_SCN_ALIGN_2BYTES: u32 = 0x200000;
615 /// pub const IMAGE_SCN_ALIGN_4BYTES: u32 = 0x300000;
616 /// pub const IMAGE_SCN_ALIGN_8BYTES: u32 = 0x400000;
617 /// pub const IMAGE_SCN_ALIGN_16BYTES: u32 = 0x500000;
618 /// pub const IMAGE_SCN_ALIGN_32BYTES: u32 = 0x600000;
619 /// pub const IMAGE_SCN_ALIGN_64BYTES: u32 = 0x700000;
620 /// pub const IMAGE_SCN_ALIGN_128BYTES: u32 = 0x800000;
621 /// pub const IMAGE_SCN_ALIGN_256BYTES: u32 = 0x900000;
622 /// pub const IMAGE_SCN_ALIGN_512BYTES: u32 = 0xA00000;
623 /// pub const IMAGE_SCN_ALIGN_1024BYTES: u32 = 0xB00000;
624 /// pub const IMAGE_SCN_ALIGN_2048BYTES: u32 = 0xC00000;
625 /// pub const IMAGE_SCN_ALIGN_4096BYTES: u32 = 0xD00000;
626 /// pub const IMAGE_SCN_ALIGN_8192BYTES: u32 = 0xE00000;
627 ALIGN: u4 = 0,
611 ALIGN: SectionHeader.Flags.Align = .NONE,
628612
629 /// The section contains extended relocations.
630 LNK_NRELOC_OVFL: u1 = 0,
613 /// The section contains extended relocations.
614 LNK_NRELOC_OVFL: bool = false,
631615
632 /// The section can be discarded as needed.
633 MEM_DISCARDABLE: u1 = 0,
616 /// The section can be discarded as needed.
617 MEM_DISCARDABLE: bool = false,
634618
635 /// The section cannot be cached.
636 MEM_NOT_CACHED: u1 = 0,
619 /// The section cannot be cached.
620 MEM_NOT_CACHED: bool = false,
637621
638 /// The section is not pageable.
639 MEM_NOT_PAGED: u1 = 0,
622 /// The section is not pageable.
623 MEM_NOT_PAGED: bool = false,
640624
641 /// The section can be shared in memory.
642 MEM_SHARED: u1 = 0,
625 /// The section can be shared in memory.
626 MEM_SHARED: bool = false,
643627
644 /// The section can be executed as code.
645 MEM_EXECUTE: u1 = 0,
628 /// The section can be executed as code.
629 MEM_EXECUTE: bool = false,
646630
647 /// The section can be read.
648 MEM_READ: u1 = 0,
631 /// The section can be read.
632 MEM_READ: bool = false,
649633
650 /// The section can be written to.
651 MEM_WRITE: u1 = 0,
634 /// The section can be written to.
635 MEM_WRITE: bool = false,
636
637 pub const Align = enum(u4) {
638 NONE = 0,
639 @"1BYTES" = 1,
640 @"2BYTES" = 2,
641 @"4BYTES" = 3,
642 @"8BYTES" = 4,
643 @"16BYTES" = 5,
644 @"32BYTES" = 6,
645 @"64BYTES" = 7,
646 @"128BYTES" = 8,
647 @"256BYTES" = 9,
648 @"512BYTES" = 10,
649 @"1024BYTES" = 11,
650 @"2048BYTES" = 12,
651 @"4096BYTES" = 13,
652 @"8192BYTES" = 14,
653 _,
654 };
655 };
652656};
653657
654658pub const Symbol = struct {
......@@ -691,7 +695,7 @@ pub const SectionNumber = enum(u16) {
691695 _,
692696};
693697
694pub const SymType = packed struct {
698pub const SymType = packed struct(u16) {
695699 complex_type: ComplexType,
696700 base_type: BaseType,
697701};
......@@ -982,87 +986,7 @@ pub const DebugInfoDefinition = struct {
982986 unused_3: [2]u8,
983987};
984988
985pub const MachineType = enum(u16) {
986 UNKNOWN = 0x0,
987 /// Alpha AXP, 32-bit address space
988 ALPHA = 0x184,
989 /// Alpha 64, 64-bit address space
990 ALPHA64 = 0x284,
991 /// Matsushita AM33
992 AM33 = 0x1d3,
993 /// x64
994 X64 = 0x8664,
995 /// ARM little endian
996 ARM = 0x1c0,
997 /// ARM64 little endian
998 ARM64 = 0xaa64,
999 /// ARM64EC
1000 ARM64EC = 0xa641,
1001 /// ARM64X
1002 ARM64X = 0xa64e,
1003 /// ARM Thumb-2 little endian
1004 ARMNT = 0x1c4,
1005 /// CEE
1006 CEE = 0xc0ee,
1007 /// CEF
1008 CEF = 0xcef,
1009 /// Hybrid PE
1010 CHPE_X86 = 0x3a64,
1011 /// EFI byte code
1012 EBC = 0xebc,
1013 /// Intel 386 or later processors and compatible processors
1014 I386 = 0x14c,
1015 /// Intel Itanium processor family
1016 IA64 = 0x200,
1017 /// LoongArch32
1018 LOONGARCH32 = 0x6232,
1019 /// LoongArch64
1020 LOONGARCH64 = 0x6264,
1021 /// Mitsubishi M32R little endian
1022 M32R = 0x9041,
1023 /// MIPS16
1024 MIPS16 = 0x266,
1025 /// MIPS with FPU
1026 MIPSFPU = 0x366,
1027 /// MIPS16 with FPU
1028 MIPSFPU16 = 0x466,
1029 /// Power PC little endian
1030 POWERPC = 0x1f0,
1031 /// Power PC with floating point support
1032 POWERPCFP = 0x1f1,
1033 /// MIPS little endian
1034 R3000 = 0x162,
1035 /// MIPS little endian
1036 R4000 = 0x166,
1037 /// MIPS little endian
1038 R10000 = 0x168,
1039 /// RISC-V 32-bit address space
1040 RISCV32 = 0x5032,
1041 /// RISC-V 64-bit address space
1042 RISCV64 = 0x5064,
1043 /// RISC-V 128-bit address space
1044 RISCV128 = 0x5128,
1045 /// Hitachi SH3
1046 SH3 = 0x1a2,
1047 /// Hitachi SH3 DSP
1048 SH3DSP = 0x1a3,
1049 /// SH3E little-endian
1050 SH3E = 0x1a4,
1051 /// Hitachi SH4
1052 SH4 = 0x1a6,
1053 /// Hitachi SH5
1054 SH5 = 0x1a8,
1055 /// Thumb
1056 THUMB = 0x1c2,
1057 /// Infineon
1058 TRICORE = 0x520,
1059 /// MIPS little-endian WCE v2
1060 WCEMIPSV2 = 0x169,
1061
1062 _,
1063};
1064
1065pub const CoffError = error{
989pub const Error = error{
1066990 InvalidPEMagic,
1067991 InvalidPEHeader,
1068992 InvalidMachine,
......@@ -1104,7 +1028,7 @@ pub const Coff = struct {
11041028
11051029 // Do some basic validation upfront
11061030 if (is_image) {
1107 const coff_header = coff.getCoffHeader();
1031 const coff_header = coff.getHeader();
11081032 if (coff_header.size_of_optional_header == 0) return error.MissingPEHeader;
11091033 }
11101034
......@@ -1161,31 +1085,31 @@ pub const Coff = struct {
11611085 return self.data[start .. start + len];
11621086 }
11631087
1164 pub fn getCoffHeader(self: Coff) CoffHeader {
1165 return @as(*align(1) const CoffHeader, @ptrCast(self.data[self.coff_header_offset..][0..@sizeOf(CoffHeader)])).*;
1088 pub fn getHeader(self: Coff) Header {
1089 return @as(*align(1) const Header, @ptrCast(self.data[self.coff_header_offset..][0..@sizeOf(Header)])).*;
11661090 }
11671091
11681092 pub fn getOptionalHeader(self: Coff) OptionalHeader {
11691093 assert(self.is_image);
1170 const offset = self.coff_header_offset + @sizeOf(CoffHeader);
1094 const offset = self.coff_header_offset + @sizeOf(Header);
11711095 return @as(*align(1) const OptionalHeader, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader)])).*;
11721096 }
11731097
1174 pub fn getOptionalHeader32(self: Coff) OptionalHeaderPE32 {
1098 pub fn getOptionalHeader32(self: Coff) OptionalHeader.PE32 {
11751099 assert(self.is_image);
1176 const offset = self.coff_header_offset + @sizeOf(CoffHeader);
1177 return @as(*align(1) const OptionalHeaderPE32, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeaderPE32)])).*;
1100 const offset = self.coff_header_offset + @sizeOf(Header);
1101 return @as(*align(1) const OptionalHeader.PE32, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader.PE32)])).*;
11781102 }
11791103
1180 pub fn getOptionalHeader64(self: Coff) OptionalHeaderPE64 {
1104 pub fn getOptionalHeader64(self: Coff) OptionalHeader.@"PE32+" {
11811105 assert(self.is_image);
1182 const offset = self.coff_header_offset + @sizeOf(CoffHeader);
1183 return @as(*align(1) const OptionalHeaderPE64, @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeaderPE64)])).*;
1106 const offset = self.coff_header_offset + @sizeOf(Header);
1107 return @as(*align(1) const OptionalHeader.@"PE32+", @ptrCast(self.data[offset..][0..@sizeOf(OptionalHeader.@"PE32+")])).*;
11841108 }
11851109
11861110 pub fn getImageBase(self: Coff) u64 {
11871111 const hdr = self.getOptionalHeader();
1188 return switch (hdr.magic) {
1112 return switch (@intFromEnum(hdr.magic)) {
11891113 IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().image_base,
11901114 IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().image_base,
11911115 else => unreachable, // We assume we have validated the header already
......@@ -1194,7 +1118,7 @@ pub const Coff = struct {
11941118
11951119 pub fn getNumberOfDataDirectories(self: Coff) u32 {
11961120 const hdr = self.getOptionalHeader();
1197 return switch (hdr.magic) {
1121 return switch (@intFromEnum(hdr.magic)) {
11981122 IMAGE_NT_OPTIONAL_HDR32_MAGIC => self.getOptionalHeader32().number_of_rva_and_sizes,
11991123 IMAGE_NT_OPTIONAL_HDR64_MAGIC => self.getOptionalHeader64().number_of_rva_and_sizes,
12001124 else => unreachable, // We assume we have validated the header already
......@@ -1203,17 +1127,17 @@ pub const Coff = struct {
12031127
12041128 pub fn getDataDirectories(self: *const Coff) []align(1) const ImageDataDirectory {
12051129 const hdr = self.getOptionalHeader();
1206 const size: usize = switch (hdr.magic) {
1207 IMAGE_NT_OPTIONAL_HDR32_MAGIC => @sizeOf(OptionalHeaderPE32),
1208 IMAGE_NT_OPTIONAL_HDR64_MAGIC => @sizeOf(OptionalHeaderPE64),
1130 const size: usize = switch (@intFromEnum(hdr.magic)) {
1131 IMAGE_NT_OPTIONAL_HDR32_MAGIC => @sizeOf(OptionalHeader.PE32),
1132 IMAGE_NT_OPTIONAL_HDR64_MAGIC => @sizeOf(OptionalHeader.@"PE32+"),
12091133 else => unreachable, // We assume we have validated the header already
12101134 };
1211 const offset = self.coff_header_offset + @sizeOf(CoffHeader) + size;
1135 const offset = self.coff_header_offset + @sizeOf(Header) + size;
12121136 return @as([*]align(1) const ImageDataDirectory, @ptrCast(self.data[offset..]))[0..self.getNumberOfDataDirectories()];
12131137 }
12141138
12151139 pub fn getSymtab(self: *const Coff) ?Symtab {
1216 const coff_header = self.getCoffHeader();
1140 const coff_header = self.getHeader();
12171141 if (coff_header.pointer_to_symbol_table == 0) return null;
12181142
12191143 const offset = coff_header.pointer_to_symbol_table;
......@@ -1222,7 +1146,7 @@ pub const Coff = struct {
12221146 }
12231147
12241148 pub fn getStrtab(self: *const Coff) error{InvalidStrtabSize}!?Strtab {
1225 const coff_header = self.getCoffHeader();
1149 const coff_header = self.getHeader();
12261150 if (coff_header.pointer_to_symbol_table == 0) return null;
12271151
12281152 const offset = coff_header.pointer_to_symbol_table + Symbol.sizeOf() * coff_header.number_of_symbols;
......@@ -1238,8 +1162,8 @@ pub const Coff = struct {
12381162 }
12391163
12401164 pub fn getSectionHeaders(self: *const Coff) []align(1) const SectionHeader {
1241 const coff_header = self.getCoffHeader();
1242 const offset = self.coff_header_offset + @sizeOf(CoffHeader) + coff_header.size_of_optional_header;
1165 const coff_header = self.getHeader();
1166 const offset = self.coff_header_offset + @sizeOf(Header) + coff_header.size_of_optional_header;
12431167 return @as([*]align(1) const SectionHeader, @ptrCast(self.data.ptr + offset))[0..coff_header.number_of_sections];
12441168 }
12451169
......@@ -1414,14 +1338,14 @@ pub const Strtab = struct {
14141338};
14151339
14161340pub const ImportHeader = extern struct {
1417 sig1: MachineType,
1341 sig1: IMAGE.FILE.MACHINE,
14181342 sig2: u16,
14191343 version: u16,
1420 machine: MachineType,
1344 machine: IMAGE.FILE.MACHINE,
14211345 time_date_stamp: u32,
14221346 size_of_data: u32,
14231347 hint: u16,
1424 types: packed struct {
1348 types: packed struct(u32) {
14251349 type: ImportType,
14261350 name_type: ImportNameType,
14271351 reserved: u11,
......@@ -1461,119 +1385,534 @@ pub const Relocation = extern struct {
14611385 type: u16,
14621386};
14631387
1464pub const ImageRelAmd64 = enum(u16) {
1465 /// The relocation is ignored.
1466 absolute = 0,
1467
1468 /// The 64-bit VA of the relocation target.
1469 addr64 = 1,
1470
1471 /// The 32-bit VA of the relocation target.
1472 addr32 = 2,
1473
1474 /// The 32-bit address without an image base.
1475 addr32nb = 3,
1476
1477 /// The 32-bit relative address from the byte following the relocation.
1478 rel32 = 4,
1479
1480 /// The 32-bit address relative to byte distance 1 from the relocation.
1481 rel32_1 = 5,
1482
1483 /// The 32-bit address relative to byte distance 2 from the relocation.
1484 rel32_2 = 6,
1485
1486 /// The 32-bit address relative to byte distance 3 from the relocation.
1487 rel32_3 = 7,
1488
1489 /// The 32-bit address relative to byte distance 4 from the relocation.
1490 rel32_4 = 8,
1491
1492 /// The 32-bit address relative to byte distance 5 from the relocation.
1493 rel32_5 = 9,
1494
1495 /// The 16-bit section index of the section that contains the target.
1496 /// This is used to support debugging information.
1497 section = 10,
1498
1499 /// The 32-bit offset of the target from the beginning of its section.
1500 /// This is used to support debugging information and static thread local storage.
1501 secrel = 11,
1502
1503 /// A 7-bit unsigned offset from the base of the section that contains the target.
1504 secrel7 = 12,
1505
1506 /// CLR tokens.
1507 token = 13,
1508
1509 /// A 32-bit signed span-dependent value emitted into the object.
1510 srel32 = 14,
1511
1512 /// A pair that must immediately follow every span-dependent value.
1513 pair = 15,
1514
1515 /// A 32-bit signed span-dependent value that is applied at link time.
1516 sspan32 = 16,
1517
1518 _,
1519};
1520
1521pub const ImageRelArm64 = enum(u16) {
1522 /// The relocation is ignored.
1523 absolute = 0,
1524
1525 /// The 32-bit VA of the target.
1526 addr32 = 1,
1527
1528 /// The 32-bit RVA of the target.
1529 addr32nb = 2,
1530
1531 /// The 26-bit relative displacement to the target, for B and BL instructions.
1532 branch26 = 3,
1533
1534 /// The page base of the target, for ADRP instruction.
1535 pagebase_rel21 = 4,
1536
1537 /// The 21-bit relative displacement to the target, for instruction ADR.
1538 rel21 = 5,
1539
1540 /// The 12-bit page offset of the target, for instructions ADD/ADDS (immediate) with zero shift.
1541 pageoffset_12a = 6,
1542
1543 /// The 12-bit page offset of the target, for instruction LDR (indexed, unsigned immediate).
1544 pageoffset_12l = 7,
1545
1546 /// The 32-bit offset of the target from the beginning of its section.
1547 /// This is used to support debugging information and static thread local storage.
1548 secrel = 8,
1549
1550 /// Bit 0:11 of section offset of the target for instructions ADD/ADDS (immediate) with zero shift.
1551 low12a = 9,
1388pub const IMAGE = struct {
1389 pub const FILE = struct {
1390 /// Machine Types
1391 /// The Machine field has one of the following values, which specify the CPU type.
1392 /// An image file can be run only on the specified machine or on a system that emulates the specified machine.
1393 pub const MACHINE = enum(u16) {
1394 /// The content of this field is assumed to be applicable to any machine type
1395 UNKNOWN = 0x0,
1396 /// Alpha AXP, 32-bit address space
1397 ALPHA = 0x184,
1398 /// Alpha 64, 64-bit address space
1399 ALPHA64 = 0x284,
1400 /// Matsushita AM33
1401 AM33 = 0x1d3,
1402 /// x64
1403 AMD64 = 0x8664,
1404 /// ARM little endian
1405 ARM = 0x1c0,
1406 /// ARM64 little endian
1407 ARM64 = 0xaa64,
1408 /// ABI that enables interoperability between native ARM64 and emulated x64 code.
1409 ARM64EC = 0xA641,
1410 /// Binary format that allows both native ARM64 and ARM64EC code to coexist in the same file.
1411 ARM64X = 0xA64E,
1412 /// ARM Thumb-2 little endian
1413 ARMNT = 0x1c4,
1414 /// EFI byte code
1415 EBC = 0xebc,
1416 /// Intel 386 or later processors and compatible processors
1417 I386 = 0x14c,
1418 /// Intel Itanium processor family
1419 IA64 = 0x200,
1420 /// LoongArch 32-bit processor family
1421 LOONGARCH32 = 0x6232,
1422 /// LoongArch 64-bit processor family
1423 LOONGARCH64 = 0x6264,
1424 /// Mitsubishi M32R little endian
1425 M32R = 0x9041,
1426 /// MIPS16
1427 MIPS16 = 0x266,
1428 /// MIPS with FPU
1429 MIPSFPU = 0x366,
1430 /// MIPS16 with FPU
1431 MIPSFPU16 = 0x466,
1432 /// Power PC little endian
1433 POWERPC = 0x1f0,
1434 /// Power PC with floating point support
1435 POWERPCFP = 0x1f1,
1436 /// MIPS I compatible 32-bit big endian
1437 R3000BE = 0x160,
1438 /// MIPS I compatible 32-bit little endian
1439 R3000 = 0x162,
1440 /// MIPS III compatible 64-bit little endian
1441 R4000 = 0x166,
1442 /// MIPS IV compatible 64-bit little endian
1443 R10000 = 0x168,
1444 /// RISC-V 32-bit address space
1445 RISCV32 = 0x5032,
1446 /// RISC-V 64-bit address space
1447 RISCV64 = 0x5064,
1448 /// RISC-V 128-bit address space
1449 RISCV128 = 0x5128,
1450 /// Hitachi SH3
1451 SH3 = 0x1a2,
1452 /// Hitachi SH3 DSP
1453 SH3DSP = 0x1a3,
1454 /// Hitachi SH4
1455 SH4 = 0x1a6,
1456 /// Hitachi SH5
1457 SH5 = 0x1a8,
1458 /// Thumb
1459 THUMB = 0x1c2,
1460 /// MIPS little-endian WCE v2
1461 WCEMIPSV2 = 0x169,
1462 _,
1463 /// AXP 64 (Same as Alpha 64)
1464 pub const AXP64: IMAGE.FILE.MACHINE = .ALPHA64;
1465 };
1466 };
15521467
1553 /// Bit 12:23 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift.
1554 high12a = 10,
1468 pub const REL = struct {
1469 /// x64 Processors
1470 /// The following relocation type indicators are defined for x64 and compatible processors.
1471 pub const AMD64 = enum(u16) {
1472 /// The relocation is ignored.
1473 ABSOLUTE = 0x0000,
1474 /// The 64-bit VA of the relocation target.
1475 ADDR64 = 0x0001,
1476 /// The 32-bit VA of the relocation target.
1477 ADDR32 = 0x0002,
1478 /// The 32-bit address without an image base (RVA).
1479 ADDR32NB = 0x0003,
1480 /// The 32-bit relative address from the byte following the relocation.
1481 REL32 = 0x0004,
1482 /// The 32-bit address relative to byte distance 1 from the relocation.
1483 REL32_1 = 0x0005,
1484 /// The 32-bit address relative to byte distance 2 from the relocation.
1485 REL32_2 = 0x0006,
1486 /// The 32-bit address relative to byte distance 3 from the relocation.
1487 REL32_3 = 0x0007,
1488 /// The 32-bit address relative to byte distance 4 from the relocation.
1489 REL32_4 = 0x0008,
1490 /// The 32-bit address relative to byte distance 5 from the relocation.
1491 REL32_5 = 0x0009,
1492 /// The 16-bit section index of the section that contains the target.
1493 /// This is used to support debugging information.
1494 SECTION = 0x000A,
1495 /// The 32-bit offset of the target from the beginning of its section.
1496 /// This is used to support debugging information and static thread local storage.
1497 SECREL = 0x000B,
1498 /// A 7-bit unsigned offset from the base of the section that contains the target.
1499 SECREL7 = 0x000C,
1500 /// CLR tokens.
1501 TOKEN = 0x000D,
1502 /// A 32-bit signed span-dependent value emitted into the object.
1503 SREL32 = 0x000E,
1504 /// A pair that must immediately follow every span-dependent value.
1505 PAIR = 0x000F,
1506 /// A 32-bit signed span-dependent value that is applied at link time.
1507 SSPAN32 = 0x0010,
1508 _,
1509 };
15551510
1556 /// Bit 0:11 of section offset of the target, for instruction LDR (indexed, unsigned immediate).
1557 low12l = 11,
1511 /// ARM Processors
1512 /// The following relocation type indicators are defined for ARM processors.
1513 pub const ARM = enum(u16) {
1514 /// The relocation is ignored.
1515 ABSOLUTE = 0x0000,
1516 /// The 32-bit VA of the target.
1517 ADDR32 = 0x0001,
1518 /// The 32-bit RVA of the target.
1519 ADDR32NB = 0x0002,
1520 /// The 24-bit relative displacement to the target.
1521 BRANCH24 = 0x0003,
1522 /// The reference to a subroutine call.
1523 /// The reference consists of two 16-bit instructions with 11-bit offsets.
1524 BRANCH11 = 0x0004,
1525 /// The 32-bit relative address from the byte following the relocation.
1526 REL32 = 0x000A,
1527 /// The 16-bit section index of the section that contains the target.
1528 /// This is used to support debugging information.
1529 SECTION = 0x000E,
1530 /// The 32-bit offset of the target from the beginning of its section.
1531 /// This is used to support debugging information and static thread local storage.
1532 SECREL = 0x000F,
1533 /// The 32-bit VA of the target.
1534 /// This relocation is applied using a MOVW instruction for the low 16 bits followed by a MOVT for the high 16 bits.
1535 MOV32 = 0x0010,
1536 /// The 32-bit VA of the target.
1537 /// This relocation is applied using a MOVW instruction for the low 16 bits followed by a MOVT for the high 16 bits.
1538 THUMB_MOV32 = 0x0011,
1539 /// The instruction is fixed up with the 21-bit relative displacement to the 2-byte aligned target.
1540 /// The least significant bit of the displacement is always zero and is not stored.
1541 /// This relocation corresponds to a Thumb-2 32-bit conditional B instruction.
1542 THUMB_BRANCH20 = 0x0012,
1543 Unused = 0x0013,
1544 /// The instruction is fixed up with the 25-bit relative displacement to the 2-byte aligned target.
1545 /// The least significant bit of the displacement is zero and is not stored.This relocation corresponds to a Thumb-2 B instruction.
1546 THUMB_BRANCH24 = 0x0014,
1547 /// The instruction is fixed up with the 25-bit relative displacement to the 4-byte aligned target.
1548 /// The low 2 bits of the displacement are zero and are not stored.
1549 /// This relocation corresponds to a Thumb-2 BLX instruction.
1550 THUMB_BLX23 = 0x0015,
1551 /// The relocation is valid only when it immediately follows a ARM_REFHI or THUMB_REFHI.
1552 /// Its SymbolTableIndex contains a displacement and not an index into the symbol table.
1553 PAIR = 0x0016,
1554 _,
1555 };
15581556
1559 /// CLR token.
1560 token = 12,
1557 /// ARM64 Processors
1558 /// The following relocation type indicators are defined for ARM64 processors.
1559 pub const ARM64 = enum(u16) {
1560 /// The relocation is ignored.
1561 ABSOLUTE = 0x0000,
1562 /// The 32-bit VA of the target.
1563 ADDR32 = 0x0001,
1564 /// The 32-bit RVA of the target.
1565 ADDR32NB = 0x0002,
1566 /// The 26-bit relative displacement to the target, for B and BL instructions.
1567 BRANCH26 = 0x0003,
1568 /// The page base of the target, for ADRP instruction.
1569 PAGEBASE_REL21 = 0x0004,
1570 /// The 12-bit relative displacement to the target, for instruction ADR
1571 REL21 = 0x0005,
1572 /// The 12-bit page offset of the target, for instructions ADD/ADDS (immediate) with zero shift.
1573 PAGEOFFSET_12A = 0x0006,
1574 /// The 12-bit page offset of the target, for instruction LDR (indexed, unsigned immediate).
1575 PAGEOFFSET_12L = 0x0007,
1576 /// The 32-bit offset of the target from the beginning of its section.
1577 /// This is used to support debugging information and static thread local storage.
1578 SECREL = 0x0008,
1579 /// Bit 0:11 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift.
1580 SECREL_LOW12A = 0x0009,
1581 /// Bit 12:23 of section offset of the target, for instructions ADD/ADDS (immediate) with zero shift.
1582 SECREL_HIGH12A = 0x000A,
1583 /// Bit 0:11 of section offset of the target, for instruction LDR (indexed, unsigned immediate).
1584 SECREL_LOW12L = 0x000B,
1585 /// CLR token.
1586 TOKEN = 0x000C,
1587 /// The 16-bit section index of the section that contains the target.
1588 /// This is used to support debugging information.
1589 SECTION = 0x000D,
1590 /// The 64-bit VA of the relocation target.
1591 ADDR64 = 0x000E,
1592 /// The 19-bit offset to the relocation target, for conditional B instruction.
1593 BRANCH19 = 0x000F,
1594 /// The 14-bit offset to the relocation target, for instructions TBZ and TBNZ.
1595 BRANCH14 = 0x0010,
1596 /// The 32-bit relative address from the byte following the relocation.
1597 REL32 = 0x0011,
1598 _,
1599 };
15611600
1562 /// The 16-bit section index of the section that contains the target.
1563 /// This is used to support debugging information.
1564 section = 13,
1601 /// Hitachi SuperH Processors
1602 /// The following relocation type indicators are defined for SH3 and SH4 processors.
1603 /// SH5-specific relocations are noted as SHM (SH Media).
1604 pub const SH = enum(u16) {
1605 /// The relocation is ignored.
1606 @"3_ABSOLUTE" = 0x0000,
1607 /// A reference to the 16-bit location that contains the VA of the target symbol.
1608 @"3_DIRECT16" = 0x0001,
1609 /// The 32-bit VA of the target symbol.
1610 @"3_DIRECT32" = 0x0002,
1611 /// A reference to the 8-bit location that contains the VA of the target symbol.
1612 @"3_DIRECT8" = 0x0003,
1613 /// A reference to the 8-bit instruction that contains the effective 16-bit VA of the target symbol.
1614 @"3_DIRECT8_WORD" = 0x0004,
1615 /// A reference to the 8-bit instruction that contains the effective 32-bit VA of the target symbol.
1616 @"3_DIRECT8_LONG" = 0x0005,
1617 /// A reference to the 8-bit location whose low 4 bits contain the VA of the target symbol.
1618 @"3_DIRECT4" = 0x0006,
1619 /// A reference to the 8-bit instruction whose low 4 bits contain the effective 16-bit VA of the target symbol.
1620 @"3_DIRECT4_WORD" = 0x0007,
1621 /// A reference to the 8-bit instruction whose low 4 bits contain the effective 32-bit VA of the target symbol.
1622 @"3_DIRECT4_LONG" = 0x0008,
1623 /// A reference to the 8-bit instruction that contains the effective 16-bit relative offset of the target symbol.
1624 @"3_PCREL8_WORD" = 0x0009,
1625 /// A reference to the 8-bit instruction that contains the effective 32-bit relative offset of the target symbol.
1626 @"3_PCREL8_LONG" = 0x000A,
1627 /// A reference to the 16-bit instruction whose low 12 bits contain the effective 16-bit relative offset of the target symbol.
1628 @"3_PCREL12_WORD" = 0x000B,
1629 /// A reference to a 32-bit location that is the VA of the section that contains the target symbol.
1630 @"3_STARTOF_SECTION" = 0x000C,
1631 /// A reference to the 32-bit location that is the size of the section that contains the target symbol.
1632 @"3_SIZEOF_SECTION" = 0x000D,
1633 /// The 16-bit section index of the section that contains the target.
1634 /// This is used to support debugging information.
1635 @"3_SECTION" = 0x000E,
1636 /// The 32-bit offset of the target from the beginning of its section.
1637 /// This is used to support debugging information and static thread local storage.
1638 @"3_SECREL" = 0x000F,
1639 /// The 32-bit RVA of the target symbol.
1640 @"3_DIRECT32_NB" = 0x0010,
1641 /// GP relative.
1642 @"3_GPREL4_LONG" = 0x0011,
1643 /// CLR token.
1644 @"3_TOKEN" = 0x0012,
1645 /// The offset from the current instruction in longwords.
1646 /// If the NOMODE bit is not set, insert the inverse of the low bit at bit 32 to select PTA or PTB.
1647 M_PCRELPT = 0x0013,
1648 /// The low 16 bits of the 32-bit address.
1649 M_REFLO = 0x0014,
1650 /// The high 16 bits of the 32-bit address.
1651 M_REFHALF = 0x0015,
1652 /// The low 16 bits of the relative address.
1653 M_RELLO = 0x0016,
1654 /// The high 16 bits of the relative address.
1655 M_RELHALF = 0x0017,
1656 /// The relocation is valid only when it immediately follows a REFHALF, RELHALF, or RELLO relocation.
1657 /// The SymbolTableIndex field of the relocation contains a displacement and not an index into the symbol table.
1658 M_PAIR = 0x0018,
1659 /// The relocation ignores section mode.
1660 M_NOMODE = 0x8000,
1661 _,
1662 };
15651663
1566 /// The 64-bit VA of the relocation target.
1567 addr64 = 14,
1664 /// IBM PowerPC Processors
1665 /// The following relocation type indicators are defined for PowerPC processors.
1666 pub const PPC = enum(u16) {
1667 /// The relocation is ignored.
1668 ABSOLUTE = 0x0000,
1669 /// The 64-bit VA of the target.
1670 ADDR64 = 0x0001,
1671 /// The 32-bit VA of the target.
1672 ADDR32 = 0x0002,
1673 /// The low 24 bits of the VA of the target.
1674 /// This is valid only when the target symbol is absolute and can be sign-extended to its original value.
1675 ADDR24 = 0x0003,
1676 /// The low 16 bits of the target's VA.
1677 ADDR16 = 0x0004,
1678 /// The low 14 bits of the target's VA.
1679 /// This is valid only when the target symbol is absolute and can be sign-extended to its original value.
1680 ADDR14 = 0x0005,
1681 /// A 24-bit PC-relative offset to the symbol's location.
1682 REL24 = 0x0006,
1683 /// A 14-bit PC-relative offset to the symbol's location.
1684 REL14 = 0x0007,
1685 /// The 32-bit RVA of the target.
1686 ADDR32NB = 0x000A,
1687 /// The 32-bit offset of the target from the beginning of its section.
1688 /// This is used to support debugging information and static thread local storage.
1689 SECREL = 0x000B,
1690 /// The 16-bit section index of the section that contains the target.
1691 /// This is used to support debugging information.
1692 SECTION = 0x000C,
1693 /// The 16-bit offset of the target from the beginning of its section.
1694 /// This is used to support debugging information and static thread local storage.
1695 SECREL16 = 0x000F,
1696 /// The high 16 bits of the target's 32-bit VA.
1697 /// This is used for the first instruction in a two-instruction sequence that loads a full address.
1698 /// This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that was taken from the location that is being relocated.
1699 REFHI = 0x0010,
1700 /// The low 16 bits of the target's VA.
1701 REFLO = 0x0011,
1702 /// A relocation that is valid only when it immediately follows a REFHI or SECRELHI relocation.
1703 /// Its SymbolTableIndex contains a displacement and not an index into the symbol table.
1704 PAIR = 0x0012,
1705 /// The low 16 bits of the 32-bit offset of the target from the beginning of its section.
1706 SECRELLO = 0x0013,
1707 /// The 16-bit signed displacement of the target relative to the GP register.
1708 GPREL = 0x0015,
1709 /// The CLR token.
1710 TOKEN = 0x0016,
1711 _,
1712 };
15681713
1569 /// The 19-bit offset to the relocation target, for conditional B instruction.
1570 branch19 = 15,
1714 /// Intel 386 Processors
1715 /// The following relocation type indicators are defined for Intel 386 and compatible processors.
1716 pub const I386 = enum(u16) {
1717 /// The relocation is ignored.
1718 ABSOLUTE = 0x0000,
1719 /// Not supported.
1720 DIR16 = 0x0001,
1721 /// Not supported.
1722 REL16 = 0x0002,
1723 /// The target's 32-bit VA.
1724 DIR32 = 0x0006,
1725 /// The target's 32-bit RVA.
1726 DIR32NB = 0x0007,
1727 /// Not supported.
1728 SEG12 = 0x0009,
1729 /// The 16-bit section index of the section that contains the target.
1730 /// This is used to support debugging information.
1731 SECTION = 0x000A,
1732 /// The 32-bit offset of the target from the beginning of its section.
1733 /// This is used to support debugging information and static thread local storage.
1734 SECREL = 0x000B,
1735 /// The CLR token.
1736 TOKEN = 0x000C,
1737 /// A 7-bit offset from the base of the section that contains the target.
1738 SECREL7 = 0x000D,
1739 /// The 32-bit relative displacement to the target.
1740 /// This supports the x86 relative branch and call instructions.
1741 REL32 = 0x0014,
1742 _,
1743 };
15711744
1572 /// The 14-bit offset to the relocation target, for instructions TBZ and TBNZ.
1573 branch14 = 16,
1745 /// Intel Itanium Processor Family (IPF)
1746 /// The following relocation type indicators are defined for the Intel Itanium processor family and compatible processors.
1747 /// Note that relocations on instructions use the bundle's offset and slot number for the relocation offset.
1748 pub const IA64 = enum(u16) {
1749 /// The relocation is ignored.
1750 ABSOLUTE = 0x0000,
1751 /// The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address before it is inserted into the specified slot in the IMM14 bundle.
1752 /// The relocation target must be absolute or the image must be fixed.
1753 IMM14 = 0x0001,
1754 /// The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address before it is inserted into the specified slot in the IMM22 bundle.
1755 /// The relocation target must be absolute or the image must be fixed.
1756 IMM22 = 0x0002,
1757 /// The slot number of this relocation must be one (1).
1758 /// The relocation can be followed by an ADDEND relocation whose value is added to the target address before it is stored in all three slots of the IMM64 bundle.
1759 IMM64 = 0x0003,
1760 /// The target's 32-bit VA.
1761 /// This is supported only for /LARGEADDRESSAWARE:NO images.
1762 DIR32 = 0x0004,
1763 /// The target's 64-bit VA.
1764 DIR64 = 0x0005,
1765 /// The instruction is fixed up with the 25-bit relative displacement to the 16-bit aligned target.
1766 /// The low 4 bits of the displacement are zero and are not stored.
1767 PCREL21B = 0x0006,
1768 /// The instruction is fixed up with the 25-bit relative displacement to the 16-bit aligned target.
1769 /// The low 4 bits of the displacement, which are zero, are not stored.
1770 PCREL21M = 0x0007,
1771 /// The LSBs of this relocation's offset must contain the slot number whereas the rest is the bundle address.
1772 /// The bundle is fixed up with the 25-bit relative displacement to the 16-bit aligned target.
1773 /// The low 4 bits of the displacement are zero and are not stored.
1774 PCREL21F = 0x0008,
1775 /// The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address and then a 22-bit GP-relative offset that is calculated and applied to the GPREL22 bundle.
1776 GPREL22 = 0x0009,
1777 /// The instruction is fixed up with the 22-bit GP-relative offset to the target symbol's literal table entry.
1778 /// The linker creates this literal table entry based on this relocation and the ADDEND relocation that might follow.
1779 LTOFF22 = 0x000A,
1780 /// The 16-bit section index of the section contains the target.
1781 /// This is used to support debugging information.
1782 SECTION = 0x000B,
1783 /// The instruction is fixed up with the 22-bit offset of the target from the beginning of its section.
1784 /// This relocation can be followed immediately by an ADDEND relocation, whose Value field contains the 32-bit unsigned offset of the target from the beginning of the section.
1785 SECREL22 = 0x000C,
1786 /// The slot number for this relocation must be one (1).
1787 /// The instruction is fixed up with the 64-bit offset of the target from the beginning of its section.
1788 /// This relocation can be followed immediately by an ADDEND relocation whose Value field contains the 32-bit unsigned offset of the target from the beginning of the section.
1789 SECREL64I = 0x000D,
1790 /// The address of data to be fixed up with the 32-bit offset of the target from the beginning of its section.
1791 SECREL32 = 0x000E,
1792 /// The target's 32-bit RVA.
1793 DIR32NB = 0x0010,
1794 /// This is applied to a signed 14-bit immediate that contains the difference between two relocatable targets.
1795 /// This is a declarative field for the linker that indicates that the compiler has already emitted this value.
1796 SREL14 = 0x0011,
1797 /// This is applied to a signed 22-bit immediate that contains the difference between two relocatable targets.
1798 /// This is a declarative field for the linker that indicates that the compiler has already emitted this value.
1799 SREL22 = 0x0012,
1800 /// This is applied to a signed 32-bit immediate that contains the difference between two relocatable values.
1801 /// This is a declarative field for the linker that indicates that the compiler has already emitted this value.
1802 SREL32 = 0x0013,
1803 /// This is applied to an unsigned 32-bit immediate that contains the difference between two relocatable values.
1804 /// This is a declarative field for the linker that indicates that the compiler has already emitted this value.
1805 UREL32 = 0x0014,
1806 /// A 60-bit PC-relative fixup that always stays as a BRL instruction of an MLX bundle.
1807 PCREL60X = 0x0015,
1808 /// A 60-bit PC-relative fixup.
1809 /// If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MBB bundle with NOP.B in slot 1 and a 25-bit BR instruction (with the 4 lowest bits all zero and dropped) in slot 2.
1810 PCREL60B = 0x0016,
1811 /// A 60-bit PC-relative fixup.
1812 /// If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MFB bundle with NOP.F in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
1813 PCREL60F = 0x0017,
1814 /// A 60-bit PC-relative fixup.
1815 /// If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MIB bundle with NOP.I in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
1816 PCREL60I = 0x0018,
1817 /// A 60-bit PC-relative fixup.
1818 /// If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MMB bundle with NOP.M in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2.
1819 PCREL60M = 0x0019,
1820 /// A 64-bit GP-relative fixup.
1821 IMMGPREL64 = 0x001a,
1822 /// A CLR token.
1823 TOKEN = 0x001b,
1824 /// A 32-bit GP-relative fixup.
1825 GPREL32 = 0x001c,
1826 /// The relocation is valid only when it immediately follows one of the following relocations: IMM14, IMM22, IMM64, GPREL22, LTOFF22, LTOFF64, SECREL22, SECREL64I, or SECREL32.
1827 /// Its value contains the addend to apply to instructions within a bundle, not for data.
1828 ADDEND = 0x001F,
1829 _,
1830 };
15741831
1575 /// The 32-bit relative address from the byte following the relocation.
1576 rel32 = 17,
1832 /// MIPS Processors
1833 /// The following relocation type indicators are defined for MIPS processors.
1834 pub const MIPS = enum(u16) {
1835 /// The relocation is ignored.
1836 ABSOLUTE = 0x0000,
1837 /// The high 16 bits of the target's 32-bit VA.
1838 REFHALF = 0x0001,
1839 /// The target's 32-bit VA.
1840 REFWORD = 0x0002,
1841 /// The low 26 bits of the target's VA.
1842 /// This supports the MIPS J and JAL instructions.
1843 JMPADDR = 0x0003,
1844 /// The high 16 bits of the target's 32-bit VA.
1845 /// This is used for the first instruction in a two-instruction sequence that loads a full address.
1846 /// This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
1847 REFHI = 0x0004,
1848 /// The low 16 bits of the target's VA.
1849 REFLO = 0x0005,
1850 /// A 16-bit signed displacement of the target relative to the GP register.
1851 GPREL = 0x0006,
1852 /// The same as IMAGE_REL_MIPS_GPREL.
1853 LITERAL = 0x0007,
1854 /// The 16-bit section index of the section contains the target.
1855 /// This is used to support debugging information.
1856 SECTION = 0x000A,
1857 /// The 32-bit offset of the target from the beginning of its section.
1858 /// This is used to support debugging information and static thread local storage.
1859 SECREL = 0x000B,
1860 /// The low 16 bits of the 32-bit offset of the target from the beginning of its section.
1861 SECRELLO = 0x000C,
1862 /// The high 16 bits of the 32-bit offset of the target from the beginning of its section.
1863 /// An IMAGE_REL_MIPS_PAIR relocation must immediately follow this one.
1864 /// The SymbolTableIndex of the PAIR relocation contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated.
1865 SECRELHI = 0x000D,
1866 /// The low 26 bits of the target's VA.
1867 /// This supports the MIPS16 JAL instruction.
1868 JMPADDR16 = 0x0010,
1869 /// The target's 32-bit RVA.
1870 REFWORDNB = 0x0022,
1871 /// The relocation is valid only when it immediately follows a REFHI or SECRELHI relocation.
1872 /// Its SymbolTableIndex contains a displacement and not an index into the symbol table.
1873 PAIR = 0x0025,
1874 _,
1875 };
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 };
15791918};
lib/std/heap.zig+21-12
......@@ -78,13 +78,15 @@ pub fn defaultQueryPageSize() usize {
7878 };
7979 var size = global.cached_result.load(.unordered);
8080 if (size > 0) return size;
81 size = switch (builtin.os.tag) {
82 .linux => if (builtin.link_libc) @intCast(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE))) else std.os.linux.getauxval(std.elf.AT_PAGESZ),
83 .driverkit, .ios, .macos, .tvos, .visionos, .watchos => blk: {
81 size = size: switch (builtin.os.tag) {
82 .linux => if (builtin.link_libc)
83 @max(std.c.sysconf(@intFromEnum(std.c._SC.PAGESIZE)), 0)
84 else
85 std.os.linux.getauxval(std.elf.AT_PAGESZ),
86 .driverkit, .ios, .macos, .tvos, .visionos, .watchos => {
8487 const task_port = std.c.mach_task_self();
8588 // mach_task_self may fail "if there are any resource failures or other errors".
86 if (task_port == std.c.TASK.NULL)
87 break :blk 0;
89 if (task_port == std.c.TASK.NULL) break :size 0;
8890 var info_count = std.c.TASK.VM.INFO_COUNT;
8991 var vm_info: std.c.task_vm_info_data_t = undefined;
9092 vm_info.page_size = 0;
......@@ -94,21 +96,28 @@ pub fn defaultQueryPageSize() usize {
9496 @as(std.c.task_info_t, @ptrCast(&vm_info)),
9597 &info_count,
9698 );
97 assert(vm_info.page_size != 0);
98 break :blk @intCast(vm_info.page_size);
99 break :size @intCast(vm_info.page_size);
99100 },
100 .windows => blk: {
101 var info: std.os.windows.SYSTEM_INFO = undefined;
102 std.os.windows.kernel32.GetSystemInfo(&info);
103 break :blk info.dwPageSize;
101 .windows => {
102 var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined;
103 switch (windows.ntdll.NtQuerySystemInformation(
104 .SystemBasicInformation,
105 &sbi,
106 @sizeOf(windows.SYSTEM_BASIC_INFORMATION),
107 null,
108 )) {
109 .SUCCESS => break :size sbi.PageSize,
110 else => break :size 0,
111 }
104112 },
105113 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)
107115 else if (builtin.os.tag == .freestanding or builtin.os.tag == .other)
108116 @compileError("unsupported target: freestanding/other")
109117 else
110118 @compileError("pageSize on " ++ @tagName(builtin.cpu.arch) ++ "-" ++ @tagName(builtin.os.tag) ++ " is not supported without linking libc, using the default implementation"),
111119 };
120 if (size == 0) size = page_size_max;
112121
113122 assert(size >= page_size_min);
114123 assert(size <= page_size_max);
src/Compilation.zig+17-9
......@@ -256,8 +256,8 @@ test_filters: []const []const u8,
256256
257257link_task_wait_group: WaitGroup = .{},
258258link_prog_node: std.Progress.Node = .none,
259link_uav_prog_node: std.Progress.Node = .none,
260link_lazy_prog_node: std.Progress.Node = .none,
259link_const_prog_node: std.Progress.Node = .none,
260link_synth_prog_node: std.Progress.Node = .none,
261261
262262llvm_opt_bisect_limit: c_int,
263263
......@@ -1982,13 +1982,13 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
19821982 };
19831983 if (have_zcu and (!need_llvm or use_llvm)) {
19841984 if (output_mode == .Obj) break :s .zcu;
1985 if (options.config.use_new_linker) break :s .zcu;
19861985 switch (target_util.zigBackend(target, use_llvm)) {
19871986 else => {},
19881987 .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) {
19891988 break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;
19901989 },
19911990 }
1991 if (options.config.use_new_linker) break :s .zcu;
19921992 }
19931993 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm
19941994 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
30813081 comp.link_prog_node = main_progress_node.start("Linking", 0);
30823082 if (lf.cast(.elf2)) |elf| {
30833083 comp.link_prog_node.increaseEstimatedTotalItems(3);
3084 comp.link_uav_prog_node = comp.link_prog_node.start("Constants", 0);
3085 comp.link_lazy_prog_node = comp.link_prog_node.start("Synthetics", 0);
3084 comp.link_const_prog_node = comp.link_prog_node.start("Constants", 0);
3085 comp.link_synth_prog_node = comp.link_prog_node.start("Synthetics", 0);
30863086 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);
30873092 }
30883093 }
30893094 defer {
30903095 comp.link_prog_node.end();
30913096 comp.link_prog_node = .none;
3092 comp.link_uav_prog_node.end();
3093 comp.link_uav_prog_node = .none;
3094 comp.link_lazy_prog_node.end();
3095 comp.link_lazy_prog_node = .none;
3097 comp.link_const_prog_node.end();
3098 comp.link_const_prog_node = .none;
3099 comp.link_synth_prog_node.end();
3100 comp.link_synth_prog_node = .none;
30963101 if (comp.bin_file) |lf| {
30973102 if (lf.cast(.elf2)) |elf| {
30983103 elf.mf.update_prog_node.end();
30993104 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;
31003108 }
31013109 }
31023110 }
src/Compilation/Config.zig+2
......@@ -438,6 +438,8 @@ pub fn resolve(options: Options) ResolveError!Config {
438438
439439 if (options.use_new_linker) |x| break :b x;
440440
441 if (target.ofmt == .coff) break :b true;
442
441443 break :b options.incremental;
442444 };
443445
src/InternPool.zig+3-3
......@@ -11919,10 +11919,10 @@ pub fn getString(ip: *InternPool, key: []const u8) OptionalNullTerminatedString
1191911919 var map_index = hash;
1192011920 while (true) : (map_index += 1) {
1192111921 map_index &= map_mask;
11922 const entry = map.at(map_index);
11923 const index = entry.acquire().unwrap() orelse return null;
11922 const entry = &map.entries[map_index];
11923 const index = entry.value.unwrap() orelse return .none;
1192411924 if (entry.hash != hash) continue;
11925 if (index.eqlSlice(key, ip)) return index;
11925 if (index.eqlSlice(key, ip)) return index.toOptional();
1192611926 }
1192711927}
1192811928
src/codegen.zig+2
......@@ -993,6 +993,8 @@ pub fn genNavRef(
993993 },
994994 .link_once => unreachable,
995995 }
996 } else if (lf.cast(.coff2)) |coff| {
997 return .{ .sym_index = @intFromEnum(try coff.navSymbol(zcu, nav_index)) };
996998 } else {
997999 const msg = try ErrorMsg.create(zcu.gpa, src_loc, "TODO genNavRef for target {}", .{target});
9981000 return .{ .fail = msg };
src/codegen/x86_64/Emit.zig+41-10
......@@ -89,6 +89,7 @@ pub fn emitMir(emit: *Emit) Error!void {
8989 }
9090 var reloc_info_buf: [2]RelocInfo = undefined;
9191 var reloc_info_index: usize = 0;
92 const ip = &emit.pt.zcu.intern_pool;
9293 while (lowered_relocs.len > 0 and
9394 lowered_relocs[0].lowered_inst_index == lowered_index) : ({
9495 lowered_relocs = lowered_relocs[1..];
......@@ -114,7 +115,6 @@ pub fn emitMir(emit: *Emit) Error!void {
114115 return error.EmitFail;
115116 },
116117 };
117 const ip = &emit.pt.zcu.intern_pool;
118118 break :target switch (ip.getNav(nav).status) {
119119 .unresolved => unreachable,
120120 .type_resolved => |type_resolved| .{
......@@ -175,6 +175,8 @@ pub fn emitMir(emit: *Emit) Error!void {
175175 coff_file.getAtom(atom).getSymbolIndex().?
176176 else |err|
177177 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))
178180 else
179181 return emit.fail("lazy symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
180182 .is_extern = false,
......@@ -190,8 +192,13 @@ pub fn emitMir(emit: *Emit) Error!void {
190192 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
191193 else if (emit.bin_file.cast(.coff)) |coff_file|
192194 try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt")
193 else
194 return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
195 else if (emit.bin_file.cast(.coff2)) |coff| @intFromEnum(try coff.globalSymbol(
196 extern_func.toSlice(&emit.lower.mir).?,
197 switch (comp.compiler_rt_strat) {
198 .none, .lib, .obj, .zcu => null,
199 .dyn_lib => "compiler_rt",
200 },
201 )) else return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
195202 .is_extern = true,
196203 .type = .symbol,
197204 },
......@@ -314,6 +321,18 @@ pub fn emitMir(emit: *Emit) Error!void {
314321 }, emit.lower.target), reloc_info),
315322 else => unreachable,
316323 }
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 }
317336 } else return emit.fail("TODO implement relocs for {s}", .{
318337 @tagName(emit.bin_file.tag),
319338 });
......@@ -683,7 +702,7 @@ pub fn emitMir(emit: *Emit) Error!void {
683702 table_reloc.source_offset,
684703 @enumFromInt(emit.atom_index),
685704 @as(i64, table_offset) + table_reloc.target_offset,
686 .{ .x86_64 = .@"32" },
705 .{ .X86_64 = .@"32" },
687706 );
688707 for (emit.lower.mir.table) |entry| {
689708 try elf.addReloc(
......@@ -691,7 +710,7 @@ pub fn emitMir(emit: *Emit) Error!void {
691710 table_offset,
692711 @enumFromInt(emit.atom_index),
693712 emit.code_offset_mapping.items[entry],
694 .{ .x86_64 = .@"64" },
713 .{ .X86_64 = .@"64" },
695714 );
696715 table_offset += ptr_size;
697716 }
......@@ -800,7 +819,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
800819 end_offset - 4,
801820 @enumFromInt(reloc.target.index),
802821 reloc.off,
803 .{ .x86_64 = .@"32" },
822 .{ .X86_64 = .@"32" },
804823 ) else if (emit.bin_file.cast(.coff)) |coff_file| {
805824 const atom_index = coff_file.getAtomIndexForSymbol(
806825 .{ .sym_index = emit.atom_index, .file = null },
......@@ -816,7 +835,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
816835 .pcrel = true,
817836 .length = 2,
818837 });
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,
820845 .branch => if (emit.bin_file.cast(.elf)) |elf_file| {
821846 const zo = elf_file.zigObjectPtr().?;
822847 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
831856 end_offset - 4,
832857 @enumFromInt(reloc.target.index),
833858 reloc.off - 4,
834 .{ .x86_64 = .PC32 },
859 .{ .X86_64 = .PC32 },
835860 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
836861 const zo = macho_file.getZigObject().?;
837862 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
863888 .pcrel = true,
864889 .length = 2,
865890 });
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}", .{
867898 @tagName(reloc.target.type), @tagName(emit.bin_file.tag),
868899 }),
869900 .tls => if (emit.bin_file.cast(.elf)) |elf_file| {
......@@ -892,7 +923,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
892923 end_offset - 4,
893924 @enumFromInt(reloc.target.index),
894925 reloc.off,
895 .{ .x86_64 = .TPOFF32 },
926 .{ .X86_64 = .TPOFF32 },
896927 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
897928 const zo = macho_file.getZigObject().?;
898929 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
src/dev.zig+2
......@@ -96,6 +96,7 @@ pub const Env = enum {
9696 .spirv_backend,
9797 .lld_linker,
9898 .coff_linker,
99 .coff2_linker,
99100 .elf_linker,
100101 .elf2_linker,
101102 .macho_linker,
......@@ -284,6 +285,7 @@ pub const Feature = enum {
284285
285286 lld_linker,
286287 coff_linker,
288 coff2_linker,
287289 elf_linker,
288290 elf2_linker,
289291 macho_linker,
src/link.zig+35-39
......@@ -610,27 +610,20 @@ pub const File = struct {
610610 }
611611 }
612612 }
613 const output_mode = comp.config.output_mode;
614 const link_mode = comp.config.link_mode;
615 base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
616 .truncate = false,
617 .read = true,
618 .mode = determineMode(output_mode, link_mode),
619 });
613 base.file = try emit.root_dir.handle.openFile(emit.sub_path, .{ .mode = .read_write });
620614 },
621 .elf2 => {
622 const elf = base.cast(.elf2).?;
623 if (base.file == null) {
624 elf.mf.file = try base.emit.root_dir.handle.createFile(base.emit.sub_path, .{
625 .truncate = false,
626 .read = true,
627 .mode = determineMode(comp.config.output_mode, comp.config.link_mode),
628 });
629 base.file = elf.mf.file;
630 try elf.mf.ensureTotalCapacity(
631 @intCast(elf.mf.nodes.items[0].location().resolve(&elf.mf)[1]),
632 );
633 }
615 .elf2, .coff2 => if (base.file == null) {
616 const mf = if (base.cast(.elf2)) |elf|
617 &elf.mf
618 else if (base.cast(.coff2)) |coff|
619 &coff.mf
620 else
621 unreachable;
622 mf.file = try base.emit.root_dir.handle.openFile(base.emit.sub_path, .{
623 .mode = .read_write,
624 });
625 base.file = mf.file;
626 try mf.ensureTotalCapacity(@intCast(mf.nodes.items[0].location().resolve(mf)[1]));
634627 },
635628 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
636629 .plan9 => unreachable,
......@@ -654,12 +647,9 @@ pub const File = struct {
654647 pub fn makeExecutable(base: *File) !void {
655648 dev.check(.make_executable);
656649 const comp = base.comp;
657 const output_mode = comp.config.output_mode;
658 const link_mode = comp.config.link_mode;
659
660 switch (output_mode) {
650 switch (comp.config.output_mode) {
661651 .Obj => return,
662 .Lib => switch (link_mode) {
652 .Lib => switch (comp.config.link_mode) {
663653 .static => return,
664654 .dynamic => {},
665655 },
......@@ -702,15 +692,18 @@ pub const File = struct {
702692 }
703693 }
704694 },
705 .elf2 => {
706 const elf = base.cast(.elf2).?;
707 if (base.file) |f| {
708 elf.mf.unmap();
709 assert(elf.mf.file.handle == f.handle);
710 elf.mf.file = undefined;
711 f.close();
712 base.file = null;
713 }
695 .elf2, .coff2 => if (base.file) |f| {
696 const mf = if (base.cast(.elf2)) |elf|
697 &elf.mf
698 else if (base.cast(.coff2)) |coff|
699 &coff.mf
700 else
701 unreachable;
702 mf.unmap();
703 assert(mf.file.handle == f.handle);
704 mf.file = undefined;
705 f.close();
706 base.file = null;
714707 },
715708 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
716709 .plan9 => unreachable,
......@@ -828,7 +821,7 @@ pub const File = struct {
828821 .spirv => {},
829822 .goff, .xcoff => {},
830823 .plan9 => unreachable,
831 .elf2 => {},
824 .elf2, .coff2 => {},
832825 inline else => |tag| {
833826 dev.check(tag.devFeature());
834827 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id);
......@@ -864,7 +857,7 @@ pub const File = struct {
864857 pub fn idle(base: *File, tid: Zcu.PerThread.Id) !bool {
865858 switch (base.tag) {
866859 else => return false,
867 inline .elf2 => |tag| {
860 inline .elf2, .coff2 => |tag| {
868861 dev.check(tag.devFeature());
869862 return @as(*tag.Type(), @fieldParentPtr("base", base)).idle(tid);
870863 },
......@@ -874,7 +867,7 @@ pub const File = struct {
874867 pub fn updateErrorData(base: *File, pt: Zcu.PerThread) !void {
875868 switch (base.tag) {
876869 else => {},
877 inline .elf2 => |tag| {
870 inline .elf2, .coff2 => |tag| {
878871 dev.check(tag.devFeature());
879872 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateErrorData(pt);
880873 },
......@@ -1155,7 +1148,7 @@ pub const File = struct {
11551148 if (base.zcu_object_basename != null) return;
11561149
11571150 switch (base.tag) {
1158 inline .elf2, .wasm => |tag| {
1151 inline .elf2, .coff2, .wasm => |tag| {
11591152 dev.check(tag.devFeature());
11601153 return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node);
11611154 },
......@@ -1165,6 +1158,7 @@ pub const File = struct {
11651158
11661159 pub const Tag = enum {
11671160 coff,
1161 coff2,
11681162 elf,
11691163 elf2,
11701164 macho,
......@@ -1179,6 +1173,7 @@ pub const File = struct {
11791173 pub fn Type(comptime tag: Tag) type {
11801174 return switch (tag) {
11811175 .coff => Coff,
1176 .coff2 => Coff2,
11821177 .elf => Elf,
11831178 .elf2 => Elf2,
11841179 .macho => MachO,
......@@ -1194,7 +1189,7 @@ pub const File = struct {
11941189
11951190 fn fromObjectFormat(ofmt: std.Target.ObjectFormat, use_new_linker: bool) Tag {
11961191 return switch (ofmt) {
1197 .coff => .coff,
1192 .coff => if (use_new_linker) .coff2 else .coff,
11981193 .elf => if (use_new_linker) .elf2 else .elf,
11991194 .macho => .macho,
12001195 .wasm => .wasm,
......@@ -1280,6 +1275,7 @@ pub const File = struct {
12801275 pub const Lld = @import("link/Lld.zig");
12811276 pub const C = @import("link/C.zig");
12821277 pub const Coff = @import("link/Coff.zig");
1278 pub const Coff2 = @import("link/Coff2.zig");
12831279 pub const Elf = @import("link/Elf.zig");
12841280 pub const Elf2 = @import("link/Elf2.zig");
12851281 pub const MachO = @import("link/MachO.zig");
src/link/Coff.zig+41-41
......@@ -125,11 +125,11 @@ const UavTable = std.AutoHashMapUnmanaged(InternPool.Index, AvMetadata);
125125const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
126126const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
127127
128const default_file_alignment: u16 = 0x200;
129const default_size_of_stack_reserve: u32 = 0x1000000;
130const default_size_of_stack_commit: u32 = 0x1000;
131const default_size_of_heap_reserve: u32 = 0x100000;
132const default_size_of_heap_commit: u32 = 0x1000;
128pub const default_file_alignment: u16 = 0x200;
129pub const default_size_of_stack_reserve: u32 = 0x1000000;
130pub const default_size_of_stack_commit: u32 = 0x1000;
131pub const default_size_of_heap_reserve: u32 = 0x100000;
132pub const default_size_of_heap_commit: u32 = 0x1000;
133133
134134const Section = struct {
135135 header: coff_util.SectionHeader,
......@@ -334,51 +334,51 @@ pub fn createEmpty(
334334 if (coff.text_section_index == null) {
335335 const file_size: u32 = @intCast(options.program_code_size_hint);
336336 coff.text_section_index = try coff.allocateSection(".text", file_size, .{
337 .CNT_CODE = 1,
338 .MEM_EXECUTE = 1,
339 .MEM_READ = 1,
337 .CNT_CODE = true,
338 .MEM_EXECUTE = true,
339 .MEM_READ = true,
340340 });
341341 }
342342
343343 if (coff.got_section_index == null) {
344344 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();
345345 coff.got_section_index = try coff.allocateSection(".got", file_size, .{
346 .CNT_INITIALIZED_DATA = 1,
347 .MEM_READ = 1,
346 .CNT_INITIALIZED_DATA = true,
347 .MEM_READ = true,
348348 });
349349 }
350350
351351 if (coff.rdata_section_index == null) {
352352 const file_size: u32 = coff.page_size;
353353 coff.rdata_section_index = try coff.allocateSection(".rdata", file_size, .{
354 .CNT_INITIALIZED_DATA = 1,
355 .MEM_READ = 1,
354 .CNT_INITIALIZED_DATA = true,
355 .MEM_READ = true,
356356 });
357357 }
358358
359359 if (coff.data_section_index == null) {
360360 const file_size: u32 = coff.page_size;
361361 coff.data_section_index = try coff.allocateSection(".data", file_size, .{
362 .CNT_INITIALIZED_DATA = 1,
363 .MEM_READ = 1,
364 .MEM_WRITE = 1,
362 .CNT_INITIALIZED_DATA = true,
363 .MEM_READ = true,
364 .MEM_WRITE = true,
365365 });
366366 }
367367
368368 if (coff.idata_section_index == null) {
369369 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * coff.ptr_width.size();
370370 coff.idata_section_index = try coff.allocateSection(".idata", file_size, .{
371 .CNT_INITIALIZED_DATA = 1,
372 .MEM_READ = 1,
371 .CNT_INITIALIZED_DATA = true,
372 .MEM_READ = true,
373373 });
374374 }
375375
376376 if (coff.reloc_section_index == null) {
377377 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff_util.BaseRelocation);
378378 coff.reloc_section_index = try coff.allocateSection(".reloc", file_size, .{
379 .CNT_INITIALIZED_DATA = 1,
380 .MEM_DISCARDABLE = 1,
381 .MEM_READ = 1,
379 .CNT_INITIALIZED_DATA = true,
380 .MEM_DISCARDABLE = true,
381 .MEM_READ = true,
382382 });
383383 }
384384
......@@ -477,7 +477,7 @@ pub fn deinit(coff: *Coff) void {
477477 coff.base_relocs.deinit(gpa);
478478}
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 {
481481 const index = @as(u16, @intCast(coff.sections.slice().len));
482482 const off = coff.findFreeSpace(size, default_file_alignment);
483483 // Memory is always allocated in sequence
......@@ -836,7 +836,7 @@ fn writeAtom(coff: *Coff, atom_index: Atom.Index, code: []u8, resolve_relocs: bo
836836 try debugMem(gpa, handle, pvaddr, mem_code);
837837 }
838838
839 if (section.header.flags.MEM_WRITE == 0) {
839 if (!section.header.flags.MEM_WRITE) {
840840 writeMemProtected(handle, pvaddr, mem_code) catch |err| {
841841 log.warn("writing to protected memory failed with error: {s}", .{@errorName(err)});
842842 };
......@@ -2227,21 +2227,21 @@ fn writeHeader(coff: *Coff) !void {
22272227 mem.writeInt(u32, buffer.writer.buffer[0x3c..][0..4], msdos_stub.len, .little);
22282228
22292229 writer.writeAll("PE\x00\x00") catch unreachable;
2230 var flags = coff_util.CoffHeaderFlags{
2231 .EXECUTABLE_IMAGE = 1,
2232 .DEBUG_STRIPPED = 1, // TODO
2230 var flags: coff_util.Header.Flags = .{
2231 .EXECUTABLE_IMAGE = true,
2232 .DEBUG_STRIPPED = true, // TODO
22332233 };
22342234 switch (coff.ptr_width) {
2235 .p32 => flags.@"32BIT_MACHINE" = 1,
2236 .p64 => flags.LARGE_ADDRESS_AWARE = 1,
2235 .p32 => flags.@"32BIT_MACHINE" = true,
2236 .p64 => flags.LARGE_ADDRESS_AWARE = true,
22372237 }
22382238 if (coff.base.comp.config.output_mode == .Lib and coff.base.comp.config.link_mode == .dynamic) {
2239 flags.DLL = 1;
2239 flags.DLL = true;
22402240 }
22412241
22422242 const timestamp = if (coff.repro) 0 else std.time.timestamp();
22432243 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 = .{
22452245 .machine = target.toCoffMachine(),
22462246 .number_of_sections = @as(u16, @intCast(coff.sections.slice().len)), // TODO what if we prune a section
22472247 .time_date_stamp = @as(u32, @truncate(@as(u64, @bitCast(timestamp)))),
......@@ -2254,10 +2254,10 @@ fn writeHeader(coff: *Coff) !void {
22542254 writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;
22552255
22562256 const dll_flags: coff_util.DllFlags = .{
2257 .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all?
2258 .DYNAMIC_BASE = 1,
2259 .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app
2260 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention
2257 .HIGH_ENTROPY_VA = true, // TODO do we want to permit non-PIE builds at all?
2258 .DYNAMIC_BASE = true,
2259 .TERMINAL_SERVER_AWARE = true, // We are not a legacy app
2260 .NX_COMPAT = true, // We are compatible with Data Execution Prevention
22612261 };
22622262 const subsystem: coff_util.Subsystem = .WINDOWS_CUI;
22632263 const size_of_image: u32 = coff.getSizeOfImage();
......@@ -2269,13 +2269,13 @@ fn writeHeader(coff: *Coff) !void {
22692269 var size_of_initialized_data: u32 = 0;
22702270 var size_of_uninitialized_data: u32 = 0;
22712271 for (coff.sections.items(.header)) |header| {
2272 if (header.flags.CNT_CODE == 1) {
2272 if (header.flags.CNT_CODE) {
22732273 size_of_code += header.size_of_raw_data;
22742274 }
2275 if (header.flags.CNT_INITIALIZED_DATA == 1) {
2275 if (header.flags.CNT_INITIALIZED_DATA) {
22762276 size_of_initialized_data += header.size_of_raw_data;
22772277 }
2278 if (header.flags.CNT_UNINITIALIZED_DATA == 1) {
2278 if (header.flags.CNT_UNINITIALIZED_DATA) {
22792279 size_of_uninitialized_data += header.size_of_raw_data;
22802280 }
22812281 }
......@@ -2283,7 +2283,7 @@ fn writeHeader(coff: *Coff) !void {
22832283 switch (coff.ptr_width) {
22842284 .p32 => {
22852285 var opt_header = coff_util.OptionalHeaderPE32{
2286 .magic = coff_util.IMAGE_NT_OPTIONAL_HDR32_MAGIC,
2286 .magic = .PE32,
22872287 .major_linker_version = 0,
22882288 .minor_linker_version = 0,
22892289 .size_of_code = size_of_code,
......@@ -2318,7 +2318,7 @@ fn writeHeader(coff: *Coff) !void {
23182318 },
23192319 .p64 => {
23202320 var opt_header = coff_util.OptionalHeaderPE64{
2321 .magic = coff_util.IMAGE_NT_OPTIONAL_HDR64_MAGIC,
2321 .magic = .@"PE32+",
23222322 .major_linker_version = 0,
23232323 .minor_linker_version = 0,
23242324 .size_of_code = size_of_code,
......@@ -2422,7 +2422,7 @@ fn allocatedVirtualSize(coff: *Coff, start: u32) u32 {
24222422
24232423fn getSizeOfHeaders(coff: Coff) u32 {
24242424 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() +
24262426 coff.getDataDirectoryHeadersSize() + coff.getSectionHeadersSize()));
24272427}
24282428
......@@ -2443,7 +2443,7 @@ fn getSectionHeadersSize(coff: Coff) u32 {
24432443
24442444fn getDataDirectoryHeadersOffset(coff: Coff) u32 {
24452445 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()));
24472447}
24482448
24492449fn getSectionHeadersOffset(coff: Coff) u32 {
......@@ -3116,7 +3116,7 @@ fn pwriteAll(coff: *Coff, bytes: []const u8, offset: u64) error{LinkFailure}!voi
31163116/// A "page" is 512 bytes.
31173117/// A "long" is 4 bytes.
31183118/// A "word" is 2 bytes.
3119const msdos_stub: [120]u8 = .{
3119pub const msdos_stub: [120]u8 = .{
31203120 'M', 'Z', // Magic number. Stands for Mark Zbikowski (designer of the MS-DOS executable format).
31213121 0x78, 0x00, // Number of bytes in the last page. This matches the size of this entire MS-DOS stub.
31223122 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 {
1111 map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
1212 pending_index: u32,
1313}),
14pending_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct {
14pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct {
1515 alignment: InternPool.Alignment,
1616 src_loc: Zcu.LazySrcLoc,
1717}),
......@@ -25,10 +25,65 @@ pub const Node = union(enum) {
2525 shdr,
2626 segment: u32,
2727 section: Symbol.Index,
28 nav: InternPool.Nav.Index,
29 uav: InternPool.Index,
30 lazy_code: InternPool.Index,
31 lazy_const_data: InternPool.Index,
28 nav: NavMapIndex,
29 uav: UavMapIndex,
30 lazy_code: LazyMapRef.Index(.code),
31 lazy_const_data: LazyMapRef.Index(.const_data),
32
33 pub const NavMapIndex = enum(u32) {
34 _,
35
36 pub fn navIndex(nmi: NavMapIndex, elf: *const Elf) InternPool.Nav.Index {
37 return elf.navs.keys()[@intFromEnum(nmi)];
38 }
39
40 pub fn symbol(nmi: NavMapIndex, elf: *const Elf) Symbol.Index {
41 return elf.navs.values()[@intFromEnum(nmi)];
42 }
43 };
44
45 pub const UavMapIndex = enum(u32) {
46 _,
47
48 pub fn uavValue(umi: UavMapIndex, elf: *const Elf) InternPool.Index {
49 return elf.uavs.keys()[@intFromEnum(umi)];
50 }
51
52 pub fn symbol(umi: UavMapIndex, elf: *const Elf) Symbol.Index {
53 return elf.uavs.values()[@intFromEnum(umi)];
54 }
55 };
56
57 pub const LazyMapRef = struct {
58 kind: link.File.LazySymbol.Kind,
59 index: u32,
60
61 pub fn Index(comptime kind: link.File.LazySymbol.Kind) type {
62 return enum(u32) {
63 _,
64
65 pub fn ref(lmi: @This()) LazyMapRef {
66 return .{ .kind = kind, .index = @intFromEnum(lmi) };
67 }
68
69 pub fn lazySymbol(lmi: @This(), elf: *const Elf) link.File.LazySymbol {
70 return lmi.ref().lazySymbol(elf);
71 }
72
73 pub fn symbol(lmi: @This(), elf: *const Elf) Symbol.Index {
74 return lmi.ref().symbol(elf);
75 }
76 };
77 }
78
79 pub fn lazySymbol(lmr: LazyMapRef, elf: *const Elf) link.File.LazySymbol {
80 return .{ .kind = lmr.kind, .ty = elf.lazy.getPtrConst(lmr.kind).map.keys()[lmr.index] };
81 }
82
83 pub fn symbol(lmr: LazyMapRef, elf: *const Elf) Symbol.Index {
84 return elf.lazy.getPtrConst(lmr.kind).map.values()[lmr.index];
85 }
86 };
3287
3388 pub const Tag = @typeInfo(Node).@"union".tag_type.?;
3489
......@@ -43,11 +98,7 @@ pub const Node = union(enum) {
4398 seg_text,
4499 seg_data,
45100 };
46 var mut_known: std.enums.EnumFieldStruct(
47 Known,
48 MappedFile.Node.Index,
49 null,
50 ) = undefined;
101 var mut_known: std.enums.EnumFieldStruct(Known, MappedFile.Node.Index, null) = undefined;
51102 for (@typeInfo(Known).@"enum".fields) |field|
52103 @field(mut_known, field.name) = @enumFromInt(field.value);
53104 break :known mut_known;
......@@ -223,10 +274,10 @@ pub const Reloc = extern struct {
223274 addend: i64,
224275
225276 pub const Type = extern union {
226 x86_64: std.elf.R_X86_64,
227 aarch64: std.elf.R_AARCH64,
228 riscv: std.elf.R_RISCV,
229 ppc64: std.elf.R_PPC64,
277 X86_64: std.elf.R_X86_64,
278 AARCH64: std.elf.R_AARCH64,
279 RISCV: std.elf.R_RISCV,
280 PPC64: std.elf.R_PPC64,
230281 };
231282
232283 pub const Index = enum(u32) {
......@@ -239,7 +290,7 @@ pub const Reloc = extern struct {
239290 };
240291
241292 pub fn apply(reloc: *const Reloc, elf: *Elf) void {
242 const target_endian = elf.endian();
293 const target_endian = elf.targetEndian();
243294 switch (reloc.loc.get(elf).ni) {
244295 .none => return,
245296 else => |ni| if (ni.hasMoved(&elf.mf)) return,
......@@ -274,7 +325,7 @@ pub const Reloc = extern struct {
274325 ) +% @as(u64, @bitCast(reloc.addend));
275326 switch (elf.ehdrField(.machine)) {
276327 else => |machine| @panic(@tagName(machine)),
277 .X86_64 => switch (reloc.type.x86_64) {
328 .X86_64 => switch (reloc.type.X86_64) {
278329 else => |kind| @panic(@tagName(kind)),
279330 .@"64" => std.mem.writeInt(
280331 u64,
......@@ -394,37 +445,7 @@ fn create(
394445 },
395446 .Obj => .REL,
396447 };
397 const machine: std.elf.EM = switch (target.cpu.arch) {
398 .spirv32, .spirv64, .wasm32, .wasm64 => .NONE,
399 .sparc => .SPARC,
400 .x86 => .@"386",
401 .m68k => .@"68K",
402 .mips, .mipsel, .mips64, .mips64el => .MIPS,
403 .powerpc, .powerpcle => .PPC,
404 .powerpc64, .powerpc64le => .PPC64,
405 .s390x => .S390,
406 .arm, .armeb, .thumb, .thumbeb => .ARM,
407 .hexagon => .SH,
408 .sparc64 => .SPARCV9,
409 .arc => .ARC,
410 .x86_64 => .X86_64,
411 .or1k => .OR1K,
412 .xtensa => .XTENSA,
413 .msp430 => .MSP430,
414 .avr => .AVR,
415 .nvptx, .nvptx64 => .CUDA,
416 .kalimba => .CSR_KALIMBA,
417 .aarch64, .aarch64_be => .AARCH64,
418 .xcore => .XCORE,
419 .amdgcn => .AMDGPU,
420 .riscv32, .riscv32be, .riscv64, .riscv64be => .RISCV,
421 .lanai => .LANAI,
422 .bpfel, .bpfeb => .BPF,
423 .ve => .VE,
424 .csky => .CSKY,
425 .loongarch32, .loongarch64 => .LOONGARCH,
426 .propeller => if (target.cpu.has(.propeller, .p2)) .PROPELLER2 else .PROPELLER,
427 };
448 const machine = target.toElfMachine();
428449 const maybe_interp = switch (comp.config.output_mode) {
429450 .Exe, .Lib => switch (comp.config.link_mode) {
430451 .static => null,
......@@ -479,7 +500,7 @@ fn create(
479500
480501 switch (class) {
481502 .NONE, _ => unreachable,
482 inline .@"32", .@"64" => |ct_class| try elf.initHeaders(
503 inline else => |ct_class| try elf.initHeaders(
483504 ct_class,
484505 data,
485506 osabi,
......@@ -567,30 +588,31 @@ fn initHeaders(
567588 .fixed = true,
568589 }));
569590 elf.nodes.appendAssumeCapacity(.ehdr);
570
571 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf)));
572 const EI = std.elf.EI;
573 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);
574 ehdr.ident[EI.CLASS] = @intFromEnum(class);
575 ehdr.ident[EI.DATA] = @intFromEnum(data);
576 ehdr.ident[EI.VERSION] = 1;
577 ehdr.ident[EI.OSABI] = @intFromEnum(osabi);
578 ehdr.ident[EI.ABIVERSION] = 0;
579 @memset(ehdr.ident[EI.PAD..], 0);
580 ehdr.type = @"type";
581 ehdr.machine = machine;
582 ehdr.version = 1;
583 ehdr.entry = 0;
584 ehdr.phoff = 0;
585 ehdr.shoff = 0;
586 ehdr.flags = 0;
587 ehdr.ehsize = @sizeOf(ElfN.Ehdr);
588 ehdr.phentsize = @sizeOf(ElfN.Phdr);
589 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);
590 ehdr.shentsize = @sizeOf(ElfN.Shdr);
591 ehdr.shnum = 1;
592 ehdr.shstrndx = 0;
593 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
591 {
592 const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf)));
593 const EI = std.elf.EI;
594 @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC);
595 ehdr.ident[EI.CLASS] = @intFromEnum(class);
596 ehdr.ident[EI.DATA] = @intFromEnum(data);
597 ehdr.ident[EI.VERSION] = 1;
598 ehdr.ident[EI.OSABI] = @intFromEnum(osabi);
599 ehdr.ident[EI.ABIVERSION] = 0;
600 @memset(ehdr.ident[EI.PAD..], 0);
601 ehdr.type = @"type";
602 ehdr.machine = machine;
603 ehdr.version = 1;
604 ehdr.entry = 0;
605 ehdr.phoff = 0;
606 ehdr.shoff = 0;
607 ehdr.flags = 0;
608 ehdr.ehsize = @sizeOf(ElfN.Ehdr);
609 ehdr.phentsize = @sizeOf(ElfN.Phdr);
610 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);
611 ehdr.shentsize = @sizeOf(ElfN.Shdr);
612 ehdr.shnum = 1;
613 ehdr.shstrndx = 0;
614 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
615 }
594616
595617 const phdr_ni = Node.known.phdr;
596618 assert(phdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{
......@@ -750,7 +772,10 @@ fn initHeaders(
750772 },
751773 .shndx = std.elf.SHN_UNDEF,
752774 };
753 ehdr.shstrndx = ehdr.shnum;
775 {
776 const ehdr = @field(elf.ehdrPtr(), @tagName(class));
777 ehdr.shstrndx = ehdr.shnum;
778 }
754779 assert(try elf.addSection(seg_rodata_ni, .{
755780 .type = std.elf.SHT_STRTAB,
756781 .addralign = elf.mf.flags.block_size,
......@@ -821,6 +846,24 @@ fn getNode(elf: *Elf, ni: MappedFile.Node.Index) Node {
821846 return elf.nodes.get(@intFromEnum(ni));
822847}
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
824867pub const EhdrPtr = union(std.elf.CLASS) {
825868 NONE: noreturn,
826869 @"32": *std.elf.Elf32.Ehdr,
......@@ -830,7 +873,7 @@ pub fn ehdrPtr(elf: *Elf) EhdrPtr {
830873 const slice = Node.known.ehdr.slice(&elf.mf);
831874 return switch (elf.identClass()) {
832875 .NONE, _ => unreachable,
833 inline .@"32", .@"64" => |class| @unionInit(
876 inline else => |class| @unionInit(
834877 EhdrPtr,
835878 @tagName(class),
836879 @ptrCast(@alignCast(slice)),
......@@ -841,35 +884,15 @@ pub fn ehdrField(
841884 elf: *Elf,
842885 comptime field: enum { type, machine },
843886) @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);
846887 return @enumFromInt(std.mem.toNative(
847 @typeInfo(Field).@"enum".tag_type,
888 @typeInfo(@FieldType(std.elf.Elf32.Ehdr, @tagName(field))).@"enum".tag_type,
848889 @intFromEnum(switch (elf.ehdrPtr()) {
849890 inline else => |ehdr| @field(ehdr, @tagName(field)),
850891 }),
851 elf.endian(),
892 elf.targetEndian(),
852893 ));
853894}
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
873896fn baseAddrForType(@"type": std.elf.ET) u64 {
874897 return switch (@"type") {
875898 else => 0,
......@@ -889,7 +912,7 @@ pub fn phdrSlice(elf: *Elf) PhdrSlice {
889912 const slice = Node.known.phdr.slice(&elf.mf);
890913 return switch (elf.identClass()) {
891914 .NONE, _ => unreachable,
892 inline .@"32", .@"64" => |class| @unionInit(
915 inline else => |class| @unionInit(
893916 PhdrSlice,
894917 @tagName(class),
895918 @ptrCast(@alignCast(slice)),
......@@ -906,7 +929,7 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice {
906929 const slice = Node.known.shdr.slice(&elf.mf);
907930 return switch (elf.identClass()) {
908931 .NONE, _ => unreachable,
909 inline .@"32", .@"64" => |class| @unionInit(
932 inline else => |class| @unionInit(
910933 ShdrSlice,
911934 @tagName(class),
912935 @ptrCast(@alignCast(slice)),
......@@ -923,7 +946,7 @@ pub fn symSlice(elf: *Elf) SymSlice {
923946 const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf);
924947 return switch (elf.identClass()) {
925948 .NONE, _ => unreachable,
926 inline .@"32", .@"64" => |class| @unionInit(
949 inline else => |class| @unionInit(
927950 SymSlice,
928951 @tagName(class),
929952 @ptrCast(@alignCast(slice)),
......@@ -942,7 +965,7 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
942965 };
943966}
944967
945fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index {
968fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index {
946969 defer elf.symtab.addOneAssumeCapacity().* = .{
947970 .ni = .none,
948971 .loc_relocs = .none,
......@@ -953,30 +976,27 @@ fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index {
953976}
954977
955978fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index {
956 const si = try elf.addSymbolAssumeCapacity();
979 const si = elf.addSymbolAssumeCapacity();
957980 try si.init(elf, opts);
958981 return si;
959982}
960983
961pub fn globalSymbol(
962 elf: *Elf,
963 opts: struct {
964 name: []const u8,
965 type: std.elf.STT,
966 bind: std.elf.STB = .GLOBAL,
967 visibility: std.elf.STV = .DEFAULT,
968 },
969) !Symbol.Index {
984pub fn globalSymbol(elf: *Elf, opts: struct {
985 name: []const u8,
986 type: std.elf.STT,
987 bind: std.elf.STB = .GLOBAL,
988 visibility: std.elf.STV = .DEFAULT,
989}) !Symbol.Index {
970990 const gpa = elf.base.comp.gpa;
971991 try elf.symtab.ensureUnusedCapacity(gpa, 1);
972 const sym_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));
973 if (!sym_gop.found_existing) sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
992 const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name));
993 if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
974994 .name = opts.name,
975995 .type = opts.type,
976996 .bind = opts.bind,
977997 .visibility = opts.visibility,
978998 });
979 return sym_gop.value_ptr.*;
999 return global_gop.value_ptr.*;
9801000}
9811001
9821002fn navType(
......@@ -1008,8 +1028,19 @@ fn navType(
10081028 },
10091029 };
10101030}
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 {
10121032 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 {
10131044 const ip = &zcu.intern_pool;
10141045 const nav = ip.getNav(nav_index);
10151046 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.
10271058 .protected => .PROTECTED,
10281059 },
10291060 });
1030 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1031 const sym_gop = try elf.navs.getOrPut(gpa, nav_index);
1032 if (!sym_gop.found_existing) {
1033 sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1034 .name = nav.fqn.toSlice(ip),
1035 .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),
1036 });
1037 }
1038 return sym_gop.value_ptr.*;
1061 const nmi = try elf.navMapIndex(zcu, nav_index);
1062 return nmi.symbol(elf);
10391063}
10401064
1041pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index {
1065fn uavMapIndex(elf: *Elf, uav_val: InternPool.Index) !Node.UavMapIndex {
10421066 const gpa = elf.base.comp.gpa;
10431067 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1044 const sym_gop = try elf.uavs.getOrPut(gpa, uav_val);
1045 if (!sym_gop.found_existing)
1046 sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT });
1047 return sym_gop.value_ptr.*;
1068 const uav_gop = try elf.uavs.getOrPut(gpa, uav_val);
1069 if (!uav_gop.found_existing)
1070 uav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT });
1071 return @enumFromInt(uav_gop.index);
1072}
1073pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index {
1074 const umi = try elf.uavMapIndex(uav_val);
1075 return umi.symbol(elf);
10481076}
10491077
10501078pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
10511079 const gpa = elf.base.comp.gpa;
10521080 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1053 const sym_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);
1054 if (!sym_gop.found_existing) {
1055 sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
1081 const lazy_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty);
1082 if (!lazy_gop.found_existing) {
1083 lazy_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
10561084 .type = switch (lazy.kind) {
10571085 .code => .FUNC,
10581086 .const_data => .OBJECT,
10591087 },
10601088 });
1061 elf.base.comp.link_lazy_prog_node.increaseEstimatedTotalItems(1);
1089 elf.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1);
10621090 }
1063 return sym_gop.value_ptr.*;
1091 return lazy_gop.value_ptr.*;
10641092}
10651093
10661094pub fn getNavVAddr(
......@@ -1088,7 +1116,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
10881116 reloc_info.addend,
10891117 switch (elf.ehdrField(.machine)) {
10901118 else => unreachable,
1091 .X86_64 => .{ .x86_64 = switch (elf.identClass()) {
1119 .X86_64 => .{ .X86_64 = switch (elf.identClass()) {
10921120 .NONE, _ => unreachable,
10931121 .@"32" => .@"32",
10941122 .@"64" => .@"64",
......@@ -1107,7 +1135,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
11071135 entsize: std.elf.Word = 0,
11081136}) !Symbol.Index {
11091137 const gpa = elf.base.comp.gpa;
1110 const target_endian = elf.endian();
1138 const target_endian = elf.targetEndian();
11111139 try elf.nodes.ensureUnusedCapacity(gpa, 1);
11121140 try elf.symtab.ensureUnusedCapacity(gpa, 1);
11131141
......@@ -1127,7 +1155,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
11271155 .size = opts.size,
11281156 .moved = true,
11291157 });
1130 const si = try elf.addSymbolAssumeCapacity();
1158 const si = elf.addSymbolAssumeCapacity();
11311159 elf.nodes.appendAssumeCapacity(.{ .section = si });
11321160 si.get(elf).ni = ni;
11331161 try si.init(elf, .{
......@@ -1160,7 +1188,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
11601188fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
11611189 const strtab_entry = try elf.string(.strtab, name);
11621190 const shstrtab_entry = try elf.string(.shstrtab, name);
1163 const target_endian = elf.endian();
1191 const target_endian = elf.targetEndian();
11641192 switch (elf.shdrSlice()) {
11651193 inline else => |shdr, class| {
11661194 const sym = @field(elf.symPtr(si), @tagName(class));
......@@ -1173,7 +1201,7 @@ fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
11731201}
11741202
11751203fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
1176 const target_endian = elf.endian();
1204 const target_endian = elf.targetEndian();
11771205 switch (elf.shdrSlice()) {
11781206 inline else => |shdr, class| {
11791207 const sym = @field(elf.symPtr(si), @tagName(class));
......@@ -1184,7 +1212,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
11841212}
11851213
11861214fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
1187 const target_endian = elf.endian();
1215 const target_endian = elf.targetEndian();
11881216 const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[name: switch (elf.shdrSlice()) {
11891217 inline else => |shndx, class| {
11901218 const sym = @field(elf.symPtr(si), @tagName(class));
......@@ -1263,7 +1291,8 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
12631291 };
12641292 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);
12671296 const ni = ni: {
12681297 const sym = si.get(elf);
12691298 switch (sym.ni) {
......@@ -1275,7 +1304,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
12751304 .alignment = pt.navAlignment(nav_index).toStdMem(),
12761305 .moved = true,
12771306 });
1278 elf.nodes.appendAssumeCapacity(.{ .nav = nav_index });
1307 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
12791308 sym.ni = ni;
12801309 switch (elf.symPtr(si)) {
12811310 inline else => |sym_ptr, class| sym_ptr.shndx =
......@@ -1289,28 +1318,24 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
12891318 break :ni sym.ni;
12901319 };
12911320
1292 const size = size: {
1293 var nw: MappedFile.Node.Writer = undefined;
1294 ni.writer(&elf.mf, gpa, &nw);
1295 defer nw.deinit();
1296 codegen.generateSymbol(
1297 &elf.base,
1298 pt,
1299 zcu.navSrcLoc(nav_index),
1300 .fromInterned(nav_init),
1301 &nw.interface,
1302 .{ .atom_index = @intFromEnum(si) },
1303 ) catch |err| switch (err) {
1304 error.WriteFailed => return error.OutOfMemory,
1305 else => |e| return e,
1306 };
1307 break :size nw.interface.end;
1321 var nw: MappedFile.Node.Writer = undefined;
1322 ni.writer(&elf.mf, gpa, &nw);
1323 defer nw.deinit();
1324 codegen.generateSymbol(
1325 &elf.base,
1326 pt,
1327 zcu.navSrcLoc(nav_index),
1328 .fromInterned(nav_init),
1329 &nw.interface,
1330 .{ .atom_index = @intFromEnum(si) },
1331 ) catch |err| switch (err) {
1332 error.WriteFailed => return error.OutOfMemory,
1333 else => |e| return e,
13081334 };
1309
1310 const target_endian = elf.endian();
1335 const target_endian = elf.targetEndian();
13111336 switch (elf.symPtr(si)) {
13121337 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),
13141339 }
13151340 si.applyLocationRelocs(elf);
13161341}
......@@ -1326,7 +1351,7 @@ pub fn lowerUav(
13261351 const gpa = zcu.gpa;
13271352
13281353 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) {
13301355 error.OutOfMemory => return error.OutOfMemory,
13311356 else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
13321357 gpa,
......@@ -1335,11 +1360,12 @@ pub fn lowerUav(
13351360 .{@errorName(e)},
13361361 ) },
13371362 };
1363 const si = umi.symbol(elf);
13381364 if (switch (si.get(elf).ni) {
13391365 .none => true,
13401366 else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt),
13411367 }) {
1342 const gop = elf.pending_uavs.getOrPutAssumeCapacity(uav_val);
1368 const gop = elf.pending_uavs.getOrPutAssumeCapacity(umi);
13431369 if (gop.found_existing) {
13441370 gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);
13451371 } else {
......@@ -1347,7 +1373,7 @@ pub fn lowerUav(
13471373 .alignment = uav_align,
13481374 .src_loc = src_loc,
13491375 };
1350 elf.base.comp.link_uav_prog_node.increaseEstimatedTotalItems(1);
1376 elf.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1);
13511377 }
13521378 }
13531379 return .{ .sym_index = @intFromEnum(si) };
......@@ -1384,7 +1410,8 @@ fn updateFuncInner(
13841410 const func = zcu.funcInfo(func_index);
13851411 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);
13881415 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });
13891416 const ni = ni: {
13901417 const sym = si.get(elf);
......@@ -1406,7 +1433,7 @@ fn updateFuncInner(
14061433 }.toStdMem(),
14071434 .moved = true,
14081435 });
1409 elf.nodes.appendAssumeCapacity(.{ .nav = func.owner_nav });
1436 elf.nodes.appendAssumeCapacity(.{ .nav = nmi });
14101437 sym.ni = ni;
14111438 switch (elf.symPtr(si)) {
14121439 inline else => |sym_ptr, class| sym_ptr.shndx =
......@@ -1420,37 +1447,35 @@ fn updateFuncInner(
14201447 break :ni sym.ni;
14211448 };
14221449
1423 const size = size: {
1424 var nw: MappedFile.Node.Writer = undefined;
1425 ni.writer(&elf.mf, gpa, &nw);
1426 defer nw.deinit();
1427 codegen.emitFunction(
1428 &elf.base,
1429 pt,
1430 zcu.navSrcLoc(func.owner_nav),
1431 func_index,
1432 @intFromEnum(si),
1433 mir,
1434 &nw.interface,
1435 .none,
1436 ) catch |err| switch (err) {
1437 error.WriteFailed => return nw.err.?,
1438 else => |e| return e,
1439 };
1440 break :size nw.interface.end;
1450 var nw: MappedFile.Node.Writer = undefined;
1451 ni.writer(&elf.mf, gpa, &nw);
1452 defer nw.deinit();
1453 codegen.emitFunction(
1454 &elf.base,
1455 pt,
1456 zcu.navSrcLoc(func.owner_nav),
1457 func_index,
1458 @intFromEnum(si),
1459 mir,
1460 &nw.interface,
1461 .none,
1462 ) catch |err| switch (err) {
1463 error.WriteFailed => return nw.err.?,
1464 else => |e| return e,
14411465 };
1442
1443 const target_endian = elf.endian();
1466 const target_endian = elf.targetEndian();
14441467 switch (elf.symPtr(si)) {
14451468 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),
14471470 }
14481471 si.applyLocationRelocs(elf);
14491472}
14501473
14511474pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void {
1452 const si = elf.lazy.getPtr(.const_data).map.get(.anyerror_type) orelse return;
1453 elf.flushLazy(pt, .{ .kind = .const_data, .ty = .anyerror_type }, si) catch |err| switch (err) {
1475 elf.flushLazy(pt, .{
1476 .kind = .const_data,
1477 .index = @intCast(elf.lazy.getPtr(.const_data).map.getIndex(.anyerror_type) orelse return),
1478 }) catch |err| switch (err) {
14541479 error.OutOfMemory => return error.OutOfMemory,
14551480 error.CodegenFail => return error.LinkFailure,
14561481 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 {
14721497 const comp = elf.base.comp;
14731498 task: {
14741499 while (elf.pending_uavs.pop()) |pending_uav| {
1475 const sub_prog_node =
1476 elf.idleProgNode(
1477 tid,
1478 comp.link_uav_prog_node,
1479 .{ .uav = pending_uav.key },
1480 );
1500 const sub_prog_node = elf.idleProgNode(
1501 tid,
1502 comp.link_const_prog_node,
1503 .{ .uav = pending_uav.key },
1504 );
14811505 defer sub_prog_node.end();
1482 break :task elf.flushUav(
1506 elf.flushUav(
14831507 .{ .zcu = elf.base.comp.zcu.?, .tid = tid },
14841508 pending_uav.key,
14851509 pending_uav.value.alignment,
......@@ -1491,37 +1515,34 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
14911515 .{e},
14921516 ),
14931517 };
1518 break :task;
14941519 }
14951520 var lazy_it = elf.lazy.iterator();
1496 while (lazy_it.next()) |lazy| for (
1497 lazy.value.map.keys()[lazy.value.pending_index..],
1498 lazy.value.map.values()[lazy.value.pending_index..],
1499 ) |ty, si| {
1500 lazy.value.pending_index += 1;
1521 while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) {
15011522 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) {
15031526 .code => "code",
15041527 .const_data => "data",
15051528 };
15061529 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(
15081531 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
15091532 kind,
1510 Type.fromInterned(ty).fmt(pt),
1533 Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt),
15111534 }) catch &name,
15121535 0,
15131536 );
15141537 defer sub_prog_node.end();
1515 break :task elf.flushLazy(pt, .{
1516 .kind = lazy.key,
1517 .ty = ty,
1518 }, si) catch |err| switch (err) {
1538 elf.flushLazy(pt, lmr) catch |err| switch (err) {
15191539 error.OutOfMemory => return error.OutOfMemory,
15201540 else => |e| return elf.base.comp.link_diags.fail(
15211541 "linker failed to lower lazy {s}: {t}",
15221542 .{ kind, e },
15231543 ),
15241544 };
1545 break :task;
15251546 };
15261547 while (elf.mf.updates.pop()) |ni| {
15271548 const clean_moved = ni.cleanMoved(&elf.mf);
......@@ -1551,12 +1572,12 @@ fn idleProgNode(
15511572 return prog_node.start(name: switch (node) {
15521573 else => |tag| @tagName(tag),
15531574 .section => |si| elf.sectionName(si),
1554 .nav => |nav| {
1575 .nav => |nmi| {
15551576 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);
15571578 },
1558 .uav => |uav| std.fmt.bufPrint(&name, "{f}", .{
1559 Value.fromInterned(uav).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
1579 .uav => |umi| std.fmt.bufPrint(&name, "{f}", .{
1580 Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
15601581 }) catch &name,
15611582 }, 0);
15621583}
......@@ -1564,14 +1585,15 @@ fn idleProgNode(
15641585fn flushUav(
15651586 elf: *Elf,
15661587 pt: Zcu.PerThread,
1567 uav_val: InternPool.Index,
1588 umi: Node.UavMapIndex,
15681589 uav_align: InternPool.Alignment,
15691590 src_loc: Zcu.LazySrcLoc,
15701591) !void {
15711592 const zcu = pt.zcu;
15721593 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);
15751597 const ni = ni: {
15761598 const sym = si.get(elf);
15771599 switch (sym.ni) {
......@@ -1581,7 +1603,7 @@ fn flushUav(
15811603 .alignment = uav_align.toStdMem(),
15821604 .moved = true,
15831605 });
1584 elf.nodes.appendAssumeCapacity(.{ .uav = uav_val });
1606 elf.nodes.appendAssumeCapacity(.{ .uav = umi });
15851607 sym.ni = ni;
15861608 switch (elf.symPtr(si)) {
15871609 inline else => |sym_ptr, class| sym_ptr.shndx =
......@@ -1598,36 +1620,34 @@ fn flushUav(
15981620 break :ni sym.ni;
15991621 };
16001622
1601 const size = size: {
1602 var nw: MappedFile.Node.Writer = undefined;
1603 ni.writer(&elf.mf, gpa, &nw);
1604 defer nw.deinit();
1605 codegen.generateSymbol(
1606 &elf.base,
1607 pt,
1608 src_loc,
1609 .fromInterned(uav_val),
1610 &nw.interface,
1611 .{ .atom_index = @intFromEnum(si) },
1612 ) catch |err| switch (err) {
1613 error.WriteFailed => return error.OutOfMemory,
1614 else => |e| return e,
1615 };
1616 break :size nw.interface.end;
1623 var nw: MappedFile.Node.Writer = undefined;
1624 ni.writer(&elf.mf, gpa, &nw);
1625 defer nw.deinit();
1626 codegen.generateSymbol(
1627 &elf.base,
1628 pt,
1629 src_loc,
1630 .fromInterned(uav_val),
1631 &nw.interface,
1632 .{ .atom_index = @intFromEnum(si) },
1633 ) catch |err| switch (err) {
1634 error.WriteFailed => return error.OutOfMemory,
1635 else => |e| return e,
16171636 };
1618
1619 const target_endian = elf.endian();
1637 const target_endian = elf.targetEndian();
16201638 switch (elf.symPtr(si)) {
16211639 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),
16231641 }
16241642 si.applyLocationRelocs(elf);
16251643}
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 {
16281646 const zcu = pt.zcu;
16291647 const gpa = zcu.gpa;
16301648
1649 const lazy = lmr.lazySymbol(elf);
1650 const si = lmr.symbol(elf);
16311651 const ni = ni: {
16321652 const sym = si.get(elf);
16331653 switch (sym.ni) {
......@@ -1639,8 +1659,8 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo
16391659 };
16401660 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true });
16411661 elf.nodes.appendAssumeCapacity(switch (lazy.kind) {
1642 .code => .{ .lazy_code = lazy.ty },
1643 .const_data => .{ .lazy_const_data = lazy.ty },
1662 .code => .{ .lazy_code = @enumFromInt(lmr.index) },
1663 .const_data => .{ .lazy_const_data = @enumFromInt(lmr.index) },
16441664 });
16451665 sym.ni = ni;
16461666 switch (elf.symPtr(si)) {
......@@ -1655,34 +1675,30 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbo
16551675 break :ni sym.ni;
16561676 };
16571677
1658 const size = size: {
1659 var required_alignment: InternPool.Alignment = .none;
1660 var nw: MappedFile.Node.Writer = undefined;
1661 ni.writer(&elf.mf, gpa, &nw);
1662 defer nw.deinit();
1663 try codegen.generateLazySymbol(
1664 &elf.base,
1665 pt,
1666 Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded,
1667 lazy,
1668 &required_alignment,
1669 &nw.interface,
1670 .none,
1671 .{ .atom_index = @intFromEnum(si) },
1672 );
1673 break :size nw.interface.end;
1674 };
1675
1676 const target_endian = elf.endian();
1678 var required_alignment: InternPool.Alignment = .none;
1679 var nw: MappedFile.Node.Writer = undefined;
1680 ni.writer(&elf.mf, gpa, &nw);
1681 defer nw.deinit();
1682 try codegen.generateLazySymbol(
1683 &elf.base,
1684 pt,
1685 Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded,
1686 lazy,
1687 &required_alignment,
1688 &nw.interface,
1689 .none,
1690 .{ .atom_index = @intFromEnum(si) },
1691 );
1692 const target_endian = elf.targetEndian();
16771693 switch (elf.symPtr(si)) {
16781694 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),
16801696 }
16811697 si.applyLocationRelocs(elf);
16821698}
16831699
16841700fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
1685 const target_endian = elf.endian();
1701 const target_endian = elf.targetEndian();
16861702 const file_offset = ni.fileLocation(&elf.mf, false).offset;
16871703 const node = elf.getNode(ni);
16881704 switch (node) {
......@@ -1738,11 +1754,8 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
17381754 .nav, .uav, .lazy_code, .lazy_const_data => {
17391755 const si = switch (node) {
17401756 else => unreachable,
1741 .nav => |nav| elf.navs.get(nav),
1742 .uav => |uav| elf.uavs.get(uav),
1743 .lazy_code => |ty| elf.lazy.getPtr(.code).map.get(ty),
1744 .lazy_const_data => |ty| elf.lazy.getPtr(.const_data).map.get(ty),
1745 }.?;
1757 inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf),
1758 };
17461759 switch (elf.shdrSlice()) {
17471760 inline else => |shdr, class| {
17481761 const sym = @field(elf.symPtr(si), @tagName(class));
......@@ -1773,7 +1786,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
17731786}
17741787
17751788fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
1776 const target_endian = elf.endian();
1789 const target_endian = elf.targetEndian();
17771790 _, const size = ni.location(&elf.mf).resolve(&elf.mf);
17781791 const node = elf.getNode(ni);
17791792 switch (node) {
......@@ -1957,65 +1970,74 @@ pub fn printNode(
19571970 indent: usize,
19581971) !void {
19591972 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);
19621973 try w.splatByteAll(' ', indent);
19631974 try w.writeAll(@tagName(node));
19641975 switch (node) {
19651976 else => {},
19661977 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),
1967 .nav => |nav_index| {
1978 .nav => |nmi| {
19681979 const zcu = elf.base.comp.zcu.?;
19691980 const ip = &zcu.intern_pool;
1970 const nav = ip.getNav(nav_index);
1981 const nav = ip.getNav(nmi.navIndex(elf));
19711982 try w.print("({f}, {f})", .{
19721983 Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }),
19731984 nav.fqn.fmt(ip),
19741985 });
19751986 },
1976 .uav => |uav| {
1987 .uav => |umi| {
19771988 const zcu = elf.base.comp.zcu.?;
1978 const val: Value = .fromInterned(uav);
1989 const val: Value = .fromInterned(umi.uavValue(elf));
19791990 try w.print("({f}, {f})", .{
19801991 val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }),
19811992 val.fmtValue(.{ .zcu = zcu, .tid = tid }),
19821993 });
19831994 },
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 }),
19842001 }
1985 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{
1986 @intFromEnum(ni),
1987 off,
1988 size,
1989 mf_node.flags.alignment.toByteUnits(),
1990 if (mf_node.flags.fixed) " fixed" else "",
1991 if (mf_node.flags.moved) " moved" else "",
1992 if (mf_node.flags.resized) " resized" else "",
1993 if (mf_node.flags.has_content) " has_content" else "",
1994 });
1995 var child_ni = mf_node.first;
1996 switch (child_ni) {
1997 .none => {
1998 const file_loc = ni.fileLocation(&elf.mf, false);
1999 if (file_loc.size == 0) return;
2000 var address = file_loc.offset;
2001 const line_len = 0x10;
2002 var line_it = std.mem.window(
2003 u8,
2004 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
2005 line_len,
2006 line_len,
2007 );
2008 while (line_it.next()) |line_bytes| : (address += line_len) {
2009 try w.splatByteAll(' ', indent + 1);
2010 try w.print("{x:0>8}", .{address});
2011 for (line_bytes) |byte| try w.print(" {x:0>2}", .{byte});
2012 try w.writeByte('\n');
2013 }
2014 },
2015 else => while (child_ni != .none) {
2016 try elf.printNode(tid, w, child_ni, indent + 1);
2017 child_ni = elf.mf.nodes.items[@intFromEnum(child_ni)].next;
2018 },
2002 {
2003 const mf_node = &elf.mf.nodes.items[@intFromEnum(ni)];
2004 const off, const size = mf_node.location().resolve(&elf.mf);
2005 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{
2006 @intFromEnum(ni),
2007 off,
2008 size,
2009 mf_node.flags.alignment.toByteUnits(),
2010 if (mf_node.flags.fixed) " fixed" else "",
2011 if (mf_node.flags.moved) " moved" else "",
2012 if (mf_node.flags.resized) " resized" else "",
2013 if (mf_node.flags.has_content) " has_content" else "",
2014 });
2015 }
2016 var leaf = true;
2017 var child_it = ni.children(&elf.mf);
2018 while (child_it.next()) |child_ni| {
2019 leaf = false;
2020 try elf.printNode(tid, w, child_ni, indent + 1);
2021 }
2022 if (leaf) {
2023 const file_loc = ni.fileLocation(&elf.mf, false);
2024 if (file_loc.size == 0) return;
2025 var address = file_loc.offset;
2026 const line_len = 0x10;
2027 var line_it = std.mem.window(
2028 u8,
2029 elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)],
2030 line_len,
2031 line_len,
2032 );
2033 while (line_it.next()) |line_bytes| : (address += line_len) {
2034 try w.splatByteAll(' ', indent + 1);
2035 try w.print("{x:0>8} ", .{address});
2036 for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte});
2037 try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1);
2038 for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.');
2039 try w.writeByte('\n');
2040 }
20192041 }
20202042}
20212043
src/link/MappedFile.zig+50-20
......@@ -34,17 +34,28 @@ pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile {
3434 .writers = .{},
3535 };
3636 errdefer mf.deinit(gpa);
37 const size: u64, const blksize = if (is_windows)
38 .{ try windows.GetFileSizeEx(file.handle), 1 }
39 else stat: {
37 const size: u64, const block_size = stat: {
38 if (is_windows) {
39 var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined;
40 break :stat .{
41 try windows.GetFileSizeEx(file.handle),
42 switch (windows.ntdll.NtQuerySystemInformation(
43 .SystemBasicInformation,
44 &sbi,
45 @sizeOf(windows.SYSTEM_BASIC_INFORMATION),
46 null,
47 )) {
48 .SUCCESS => @max(sbi.PageSize, sbi.AllocationGranularity),
49 else => std.heap.page_size_max,
50 },
51 };
52 }
4053 const stat = try std.posix.fstat(mf.file.handle);
4154 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) };
4356 };
4457 mf.flags = .{
45 .block_size = .fromByteUnits(
46 std.math.ceilPowerOfTwoAssert(usize, @max(std.heap.pageSize(), blksize)),
47 ),
58 .block_size = .fromByteUnits(std.math.ceilPowerOfTwoAssert(usize, block_size)),
4859 .copy_file_range_unsupported = false,
4960 .fallocate_insert_range_unsupported = false,
5061 .fallocate_punch_hole_unsupported = false,
......@@ -90,9 +101,11 @@ pub const Node = extern struct {
90101 resized: bool,
91102 /// Whether this node might contain non-zero bytes.
92103 has_content: bool,
104 /// Whether a moved event on this node bubbles down to children.
105 bubbles_moved: bool,
93106 unused: @Type(.{ .int = .{
94107 .signedness = .unsigned,
95 .bits = 32 - @bitSizeOf(std.mem.Alignment) - 5,
108 .bits = 32 - @bitSizeOf(std.mem.Alignment) - 6,
96109 } }) = 0,
97110 };
98111
......@@ -136,6 +149,25 @@ pub const Node = extern struct {
136149 return &mf.nodes.items[@intFromEnum(ni)];
137150 }
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
139171 pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void {
140172 var child_ni = ni.get(mf).last;
141173 while (child_ni != .none) {
......@@ -147,9 +179,10 @@ pub const Node = extern struct {
147179 pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool {
148180 var parent_ni = ni;
149181 while (parent_ni != Node.Index.root) {
150 const parent = parent_ni.get(mf);
151 if (parent.flags.moved) return true;
152 parent_ni = parent.parent;
182 const parent_node = parent_ni.get(mf);
183 if (!parent_node.flags.bubbles_moved) break;
184 if (parent_node.flags.moved) return true;
185 parent_ni = parent_node.parent;
153186 }
154187 return false;
155188 }
......@@ -163,12 +196,7 @@ pub const Node = extern struct {
163196 return node_moved.*;
164197 }
165198 fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
166 var parent_ni = ni;
167 while (parent_ni != Node.Index.root) {
168 const parent_node = parent_ni.get(mf);
169 if (parent_node.flags.moved) return;
170 parent_ni = parent_node.parent;
171 }
199 if (ni.hasMoved(mf)) return;
172200 const node = ni.get(mf);
173201 node.flags.moved = true;
174202 if (node.flags.resized) return;
......@@ -242,10 +270,10 @@ pub const Node = extern struct {
242270 var offset, const size = ni.location(mf).resolve(mf);
243271 var parent_ni = ni;
244272 while (true) {
245 const parent = parent_ni.get(mf);
246 if (set_has_content) parent.flags.has_content = true;
273 const parent_node = parent_ni.get(mf);
274 if (set_has_content) parent_node.flags.has_content = true;
247275 if (parent_ni == .none) break;
248 parent_ni = parent.parent;
276 parent_ni = parent_node.parent;
249277 offset += parent_ni.location(mf).resolve(mf)[0];
250278 }
251279 return .{ .offset = offset, .size = size };
......@@ -449,6 +477,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
449477 .moved = true,
450478 .resized = true,
451479 .has_content = false,
480 .bubbles_moved = opts.add_node.bubbles_moved,
452481 },
453482 .location_payload = location_payload,
454483 };
......@@ -471,6 +500,7 @@ pub const AddNodeOptions = struct {
471500 fixed: bool = false,
472501 moved: bool = false,
473502 resized: bool = false,
503 bubbles_moved: bool = true,
474504};
475505
476506pub fn addOnlyChildNode(
src/target.zig+1-1
......@@ -233,7 +233,7 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
233233
234234pub fn hasNewLinkerSupport(ofmt: std.Target.ObjectFormat, backend: std.builtin.CompilerBackend) bool {
235235 return switch (ofmt) {
236 .elf => switch (backend) {
236 .elf, .coff => switch (backend) {
237237 .stage2_x86_64 => true,
238238 else => false,
239239 },
test/behavior/cast.zig-2
......@@ -1650,7 +1650,6 @@ test "coerce between pointers of compatible differently-named floats" {
16501650 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;
16511651 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16521652 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;
16541653 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16551654
16561655 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
......@@ -2883,7 +2882,6 @@ test "@intFromFloat vector boundary cases" {
28832882 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
28842883 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
28852884 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
28882886 const S = struct {
28892887 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 {
4343}
4444
4545test "export function alias" {
46 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt == .coff) return error.SkipZigTest;
4746 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4847
4948 _ = struct {
test/behavior/extern.zig-2
......@@ -16,7 +16,6 @@ export var a_mystery_symbol: i32 = 1234;
1616
1717test "function extern symbol" {
1818 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;
2019 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2120
2221 const a = @extern(*const fn () callconv(.c) i32, .{ .name = "a_mystery_function" });
......@@ -29,7 +28,6 @@ export fn a_mystery_function() i32 {
2928
3029test "function extern symbol matches extern decl" {
3130 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;
3331 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3432
3533 const S = struct {
test/behavior/floatop.zig-17
......@@ -158,7 +158,6 @@ test "cmp f80/c_longdouble" {
158158 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
159159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
160160 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
163162 try testCmp(f80);
164163 try comptime testCmp(f80);
......@@ -283,7 +282,6 @@ test "vector cmp f80/c_longdouble" {
283282 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
284283 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
285284 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
288286 try testCmpVector(f80);
289287 try comptime testCmpVector(f80);
......@@ -396,7 +394,6 @@ test "@sqrt f80/f128/c_longdouble" {
396394 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
397395 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
398396 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
401398 if (builtin.os.tag == .freebsd) {
402399 // TODO https://github.com/ziglang/zig/issues/10875
......@@ -526,7 +523,6 @@ test "@sin f80/f128/c_longdouble" {
526523 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
527524 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
528525 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
531527 try testSin(f80);
532528 comptime try testSin(f80);
......@@ -596,7 +592,6 @@ test "@cos f80/f128/c_longdouble" {
596592 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
597593 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
598594 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
601596 try testCos(f80);
602597 try comptime testCos(f80);
......@@ -666,7 +661,6 @@ test "@tan f80/f128/c_longdouble" {
666661 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
667662 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
668663 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
671665 try testTan(f80);
672666 try comptime testTan(f80);
......@@ -736,7 +730,6 @@ test "@exp f80/f128/c_longdouble" {
736730 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
737731 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
738732 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
741734 try testExp(f80);
742735 try comptime testExp(f80);
......@@ -810,7 +803,6 @@ test "@exp2 f80/f128/c_longdouble" {
810803 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
811804 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
812805 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
815807 try testExp2(f80);
816808 try comptime testExp2(f80);
......@@ -879,7 +871,6 @@ test "@log f80/f128/c_longdouble" {
879871 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
880872 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
881873 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
884875 try testLog(f80);
885876 try comptime testLog(f80);
......@@ -946,7 +937,6 @@ test "@log2 f80/f128/c_longdouble" {
946937 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
947938 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
948939 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
951941 try testLog2(f80);
952942 try comptime testLog2(f80);
......@@ -1019,7 +1009,6 @@ test "@log10 f80/f128/c_longdouble" {
10191009 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10201010 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10211011 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
10241013 try testLog10(f80);
10251014 try comptime testLog10(f80);
......@@ -1086,7 +1075,6 @@ test "@abs f80/f128/c_longdouble" {
10861075 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10871076 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10881077 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
10911079 try testFabs(f80);
10921080 try comptime testFabs(f80);
......@@ -1204,7 +1192,6 @@ test "@floor f80/f128/c_longdouble" {
12041192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12051193 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
12061194 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;
12081195 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12091196 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12101197
......@@ -1295,7 +1282,6 @@ test "@ceil f80/f128/c_longdouble" {
12951282 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12961283 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
12971284 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;
12991285 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13001286 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13011287
......@@ -1388,7 +1374,6 @@ test "@trunc f80/f128/c_longdouble" {
13881374 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13891375 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13901376 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
13931378 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) {
13941379 // https://github.com/ziglang/zig/issues/12602
......@@ -1485,7 +1470,6 @@ test "neg f80/f128/c_longdouble" {
14851470 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14861471 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
14871472 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
14901474 try testNeg(f80);
14911475 try comptime testNeg(f80);
......@@ -1741,7 +1725,6 @@ test "comptime calls are only memoized when float arguments are bit-for-bit equa
17411725test "result location forwarded through unary float builtins" {
17421726 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
17431727 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;
17451728 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
17461729 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" {
3131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3232 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3333 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;
3534 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3635
3736 try std.testing.expect(int == .c_keyword_variable);
test/behavior/math.zig+6-4
......@@ -1416,7 +1416,6 @@ test "remainder division" {
14161416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14171417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14181418 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;
14201419 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
14211420 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14221421
......@@ -1425,6 +1424,8 @@ test "remainder division" {
14251424 return error.SkipZigTest;
14261425 }
14271426
1427 if (builtin.zig_backend == .stage2_x86_64 and builtin.object_format == .coff and builtin.abi != .gnu) return error.SkipZigTest;
1428
14281429 try comptime remdiv(f16);
14291430 try comptime remdiv(f32);
14301431 try comptime remdiv(f64);
......@@ -1496,9 +1497,10 @@ test "float modulo division using @mod" {
14961497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14971498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14981499 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;
15001500 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
15021504 try comptime fmod(f16);
15031505 try comptime fmod(f32);
15041506 try comptime fmod(f64);
......@@ -1686,7 +1688,6 @@ test "signed zeros are represented properly" {
16861688 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16871689 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16881690 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
16911692 const S = struct {
16921693 fn doTheTest() !void {
......@@ -1824,7 +1825,8 @@ test "float divide by zero" {
18241825 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18251826 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
18261827 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
18291831 const S = struct {
18301832 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" {
1414 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1616 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;
1817 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1918
2019 @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 {
52555255 return @mod(lhs, rhs);
52565256}
52575257test 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;
52595260 const test_mod = binary(mod, .{});
52605261 try test_mod.testInts();
52615262 try test_mod.testIntVectors();
test/incremental/add_decl+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45//#target=wasm32-wasi-selfhosted
test/incremental/add_decl_namespaced+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45//#target=wasm32-wasi-selfhosted
test/incremental/analysis_error_and_syntax_error+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/bad_import+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/change_embed_file+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/change_enum_tag_type+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/change_exports+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45
test/incremental/change_fn_type+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#update=initial version
test/incremental/change_generic_line_number+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=wasm32-wasi-selfhosted
34#update=initial version
45#file=main.zig
test/incremental/change_line_number+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=wasm32-wasi-selfhosted
34#update=initial version
45#file=main.zig
test/incremental/change_module+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/change_panic_handler+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#update=initial version
test/incremental/change_panic_handler_explicit+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#update=initial version
test/incremental/change_shift_op+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/change_struct_same_fields+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/change_zon_file+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45//#target=wasm32-wasi-selfhosted
test/incremental/change_zon_file_no_result_type+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45//#target=wasm32-wasi-selfhosted
test/incremental/compile_error_then_log+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/compile_log+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/delete_comptime_decls+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/dependency_on_type_of_inferred_global+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/fix_astgen_failure+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/function_becomes_inline+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#update=non-inline version
test/incremental/hello+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/make_decl_pub+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/modify_inline_fn+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/move_src+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/no_change_preserves_tag_names+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45//#target=wasm32-wasi-selfhosted
test/incremental/recursive_function_becomes_non_recursive+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/remove_enum_field+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/remove_invalid_union_backing_enum+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/temporary_parse_error+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/type_becomes_comptime_only+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted
test/incremental/unreferenced_error+1
......@@ -1,4 +1,5 @@
11#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
23#target=x86_64-linux-cbe
34#target=x86_64-windows-cbe
45#target=wasm32-wasi-selfhosted