| author | |
| committer | |
| log | 69ce7f0e085b5fb3bf7356e9999940c60c79cfe2 |
| tree | 564b875b1be006deeb3931d4a9252a836b195e44 |
| parent | 3bcdca07a37d29256c56c2b681d43d74cd0f88b5 |
| parent | 710a3b37e2f51010dcb37e4d39ba9ac77eddbd82 |
| signature |
Some additions to `std.elf` addressing #19830, plus some zld improvements3 files changed, 137 insertions(+), 37 deletions(-)
lib/std/elf.zig+90-14| ... | @@ -453,18 +453,27 @@ pub const ET = enum(u16) { | ... | @@ -453,18 +453,27 @@ pub const ET = enum(u16) { |
| 453 | /// Core file | 453 | /// Core file |
| 454 | CORE = 4, | 454 | CORE = 4, |
| 455 | 455 | ||
| 456 | /// Beginning of OS-specific codes | ||
| 457 | pub const LOOS = 0xfe00; | ||
| 458 | |||
| 459 | /// End of OS-specific codes | ||
| 460 | pub const HIOS = 0xfeff; | ||
| 461 | |||
| 456 | /// Beginning of processor-specific codes | 462 | /// Beginning of processor-specific codes |
| 457 | pub const LOPROC = 0xff00; | 463 | pub const LOPROC = 0xff00; |
| 458 | 464 | ||
| 459 | /// Processor-specific | 465 | /// End of processor-specific codes |
| 460 | pub const HIPROC = 0xffff; | 466 | pub const HIPROC = 0xffff; |
| 461 | }; | 467 | }; |
| 462 | 468 | ||
| 463 | /// All integers are native endian. | 469 | /// All integers are native endian. |
| 464 | pub const Header = struct { | 470 | pub const Header = struct { |
| 471 | is_64: bool, | ||
| 465 | endian: std.builtin.Endian, | 472 | endian: std.builtin.Endian, |
| 473 | os_abi: OSABI, | ||
| 474 | abi_version: u8, | ||
| 475 | type: ET, | ||
| 466 | machine: EM, | 476 | machine: EM, |
| 467 | is_64: bool, | ||
| 468 | entry: u64, | 477 | entry: u64, |
| 469 | phoff: u64, | 478 | phoff: u64, |
| 470 | shoff: u64, | 479 | shoff: u64, |
| ... | @@ -501,6 +510,12 @@ pub const Header = struct { | ... | @@ -501,6 +510,12 @@ pub const Header = struct { |
| 501 | if (!mem.eql(u8, hdr32.e_ident[0..4], MAGIC)) return error.InvalidElfMagic; | 510 | if (!mem.eql(u8, hdr32.e_ident[0..4], MAGIC)) return error.InvalidElfMagic; |
| 502 | if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion; | 511 | if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion; |
| 503 | 512 | ||
| 513 | const is_64 = switch (hdr32.e_ident[EI_CLASS]) { | ||
| 514 | ELFCLASS32 => false, | ||
| 515 | ELFCLASS64 => true, | ||
| 516 | else => return error.InvalidElfClass, | ||
| 517 | }; | ||
| 518 | |||
| 504 | const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) { | 519 | const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) { |
| 505 | ELFDATA2LSB => .little, | 520 | ELFDATA2LSB => .little, |
| 506 | ELFDATA2MSB => .big, | 521 | ELFDATA2MSB => .big, |
| ... | @@ -508,11 +523,15 @@ pub const Header = struct { | ... | @@ -508,11 +523,15 @@ pub const Header = struct { |
| 508 | }; | 523 | }; |
| 509 | const need_bswap = endian != native_endian; | 524 | const need_bswap = endian != native_endian; |
| 510 | 525 | ||
| 511 | const is_64 = switch (hdr32.e_ident[EI_CLASS]) { | 526 | const os_abi: OSABI = @enumFromInt(hdr32.e_ident[EI_OSABI]); |
| 512 | ELFCLASS32 => false, | 527 | |
| 513 | ELFCLASS64 => true, | 528 | // The meaning of this value depends on `os_abi` so just make it available as `u8`. |
| 514 | else => return error.InvalidElfClass, | 529 | const abi_version = hdr32.e_ident[EI_ABIVERSION]; |
| 515 | }; | 530 | |
| 531 | const @"type" = if (need_bswap) blk: { | ||
| 532 | const value = @intFromEnum(hdr32.e_type); | ||
| 533 | break :blk @as(ET, @enumFromInt(@byteSwap(value))); | ||
| 534 | } else hdr32.e_type; | ||
| 516 | 535 | ||
| 517 | const machine = if (need_bswap) blk: { | 536 | const machine = if (need_bswap) blk: { |
| 518 | const value = @intFromEnum(hdr32.e_machine); | 537 | const value = @intFromEnum(hdr32.e_machine); |
| ... | @@ -520,9 +539,12 @@ pub const Header = struct { | ... | @@ -520,9 +539,12 @@ pub const Header = struct { |
| 520 | } else hdr32.e_machine; | 539 | } else hdr32.e_machine; |
| 521 | 540 | ||
| 522 | return @as(Header, .{ | 541 | return @as(Header, .{ |
| 542 | .is_64 = is_64, | ||
| 523 | .endian = endian, | 543 | .endian = endian, |
| 544 | .os_abi = os_abi, | ||
| 545 | .abi_version = abi_version, | ||
| 546 | .type = @"type", | ||
| 524 | .machine = machine, | 547 | .machine = machine, |
| 525 | .is_64 = is_64, | ||
| 526 | .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry), | 548 | .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry), |
| 527 | .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff), | 549 | .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff), |
| 528 | .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff), | 550 | .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff), |
| ... | @@ -637,7 +659,7 @@ pub fn SectionHeaderIterator(comptime ParseSource: anytype) type { | ... | @@ -637,7 +659,7 @@ pub fn SectionHeaderIterator(comptime ParseSource: anytype) type { |
| 637 | }; | 659 | }; |
| 638 | } | 660 | } |
| 639 | 661 | ||
| 640 | pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) { | 662 | fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) { |
| 641 | if (is_64) { | 663 | if (is_64) { |
| 642 | if (need_bswap) { | 664 | if (need_bswap) { |
| 643 | return @byteSwap(int_64); | 665 | return @byteSwap(int_64); |
| ... | @@ -649,7 +671,7 @@ pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @Typ | ... | @@ -649,7 +671,7 @@ pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @Typ |
| 649 | } | 671 | } |
| 650 | } | 672 | } |
| 651 | 673 | ||
| 652 | pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 { | 674 | fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 { |
| 653 | if (need_bswap) { | 675 | if (need_bswap) { |
| 654 | return @byteSwap(int_32); | 676 | return @byteSwap(int_32); |
| 655 | } else { | 677 | } else { |
| ... | @@ -657,21 +679,24 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 { | ... | @@ -657,21 +679,24 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 { |
| 657 | } | 679 | } |
| 658 | } | 680 | } |
| 659 | 681 | ||
| 660 | pub const EI_NIDENT = 16; | ||
| 661 | |||
| 662 | pub const EI_CLASS = 4; | ||
| 663 | pub const ELFCLASSNONE = 0; | 682 | pub const ELFCLASSNONE = 0; |
| 664 | pub const ELFCLASS32 = 1; | 683 | pub const ELFCLASS32 = 1; |
| 665 | pub const ELFCLASS64 = 2; | 684 | pub const ELFCLASS64 = 2; |
| 666 | pub const ELFCLASSNUM = 3; | 685 | pub const ELFCLASSNUM = 3; |
| 667 | 686 | ||
| 668 | pub const EI_DATA = 5; | ||
| 669 | pub const ELFDATANONE = 0; | 687 | pub const ELFDATANONE = 0; |
| 670 | pub const ELFDATA2LSB = 1; | 688 | pub const ELFDATA2LSB = 1; |
| 671 | pub const ELFDATA2MSB = 2; | 689 | pub const ELFDATA2MSB = 2; |
| 672 | pub const ELFDATANUM = 3; | 690 | pub const ELFDATANUM = 3; |
| 673 | 691 | ||
| 692 | pub const EI_CLASS = 4; | ||
| 693 | pub const EI_DATA = 5; | ||
| 674 | pub const EI_VERSION = 6; | 694 | pub const EI_VERSION = 6; |
| 695 | pub const EI_OSABI = 7; | ||
| 696 | pub const EI_ABIVERSION = 8; | ||
| 697 | pub const EI_PAD = 9; | ||
| 698 | |||
| 699 | pub const EI_NIDENT = 16; | ||
| 675 | 700 | ||
| 676 | pub const Elf32_Half = u16; | 701 | pub const Elf32_Half = u16; |
| 677 | pub const Elf64_Half = u16; | 702 | pub const Elf64_Half = u16; |
| ... | @@ -1094,6 +1119,57 @@ pub const Addr = switch (@sizeOf(usize)) { | ... | @@ -1094,6 +1119,57 @@ pub const Addr = switch (@sizeOf(usize)) { |
| 1094 | }; | 1119 | }; |
| 1095 | pub const Half = u16; | 1120 | pub const Half = u16; |
| 1096 | 1121 | ||
| 1122 | pub const OSABI = enum(u8) { | ||
| 1123 | /// UNIX System V ABI | ||
| 1124 | NONE = 0, | ||
| 1125 | /// HP-UX operating system | ||
| 1126 | HPUX = 1, | ||
| 1127 | /// NetBSD | ||
| 1128 | NETBSD = 2, | ||
| 1129 | /// GNU (Hurd/Linux) | ||
| 1130 | GNU = 3, | ||
| 1131 | /// Solaris | ||
| 1132 | SOLARIS = 6, | ||
| 1133 | /// AIX | ||
| 1134 | AIX = 7, | ||
| 1135 | /// IRIX | ||
| 1136 | IRIX = 8, | ||
| 1137 | /// FreeBSD | ||
| 1138 | FREEBSD = 9, | ||
| 1139 | /// TRU64 UNIX | ||
| 1140 | TRU64 = 10, | ||
| 1141 | /// Novell Modesto | ||
| 1142 | MODESTO = 11, | ||
| 1143 | /// OpenBSD | ||
| 1144 | OPENBSD = 12, | ||
| 1145 | /// OpenVMS | ||
| 1146 | OPENVMS = 13, | ||
| 1147 | /// Hewlett-Packard Non-Stop Kernel | ||
| 1148 | NSK = 14, | ||
| 1149 | /// AROS | ||
| 1150 | AROS = 15, | ||
| 1151 | /// FenixOS | ||
| 1152 | FENIXOS = 16, | ||
| 1153 | /// Nuxi CloudABI | ||
| 1154 | CLOUDABI = 17, | ||
| 1155 | /// Stratus Technologies OpenVOS | ||
| 1156 | OPENVOS = 18, | ||
| 1157 | /// NVIDIA CUDA architecture | ||
| 1158 | CUDA = 51, | ||
| 1159 | /// AMD HSA Runtime | ||
| 1160 | AMDGPU_HSA = 64, | ||
| 1161 | /// AMD PAL Runtime | ||
| 1162 | AMDGPU_PAL = 65, | ||
| 1163 | /// AMD Mesa3D Runtime | ||
| 1164 | AMDGPU_MESA3D = 66, | ||
| 1165 | /// ARM | ||
| 1166 | ARM = 97, | ||
| 1167 | /// Standalone (embedded) application | ||
| 1168 | STANDALONE = 255, | ||
| 1169 | |||
| 1170 | _, | ||
| 1171 | }; | ||
| 1172 | |||
| 1097 | /// Machine architectures. | 1173 | /// Machine architectures. |
| 1098 | /// | 1174 | /// |
| 1099 | /// See current registered ELF machine architectures at: | 1175 | /// See current registered ELF machine architectures at: |
src/link/Elf.zig+20-3| ... | @@ -2584,11 +2584,28 @@ pub fn writeElfHeader(self: *Elf) !void { | ... | @@ -2584,11 +2584,28 @@ pub fn writeElfHeader(self: *Elf) !void { |
| 2584 | hdr_buf[index] = 1; // ELF version | 2584 | hdr_buf[index] = 1; // ELF version |
| 2585 | index += 1; | 2585 | index += 1; |
| 2586 | 2586 | ||
| 2587 | // OS ABI, often set to 0 regardless of target platform | 2587 | hdr_buf[index] = @intFromEnum(@as(elf.OSABI, switch (target.cpu.arch) { |
| 2588 | .amdgcn => switch (target.os.tag) { | ||
| 2589 | .amdhsa => .AMDGPU_HSA, | ||
| 2590 | .amdpal => .AMDGPU_PAL, | ||
| 2591 | .mesa3d => .AMDGPU_MESA3D, | ||
| 2592 | else => .NONE, | ||
| 2593 | }, | ||
| 2594 | .msp430 => .STANDALONE, | ||
| 2595 | else => switch (target.os.tag) { | ||
| 2596 | .freebsd, .ps4 => .FREEBSD, | ||
| 2597 | .hermit => .STANDALONE, | ||
| 2598 | .illumos, .solaris => .SOLARIS, | ||
| 2599 | .openbsd => .OPENBSD, | ||
| 2600 | else => .NONE, | ||
| 2601 | }, | ||
| 2602 | })); | ||
| 2603 | index += 1; | ||
| 2604 | |||
| 2588 | // ABI Version, possibly used by glibc but not by static executables | 2605 | // ABI Version, possibly used by glibc but not by static executables |
| 2589 | // padding | 2606 | // padding |
| 2590 | @memset(hdr_buf[index..][0..9], 0); | 2607 | @memset(hdr_buf[index..][0..8], 0); |
| 2591 | index += 9; | 2608 | index += 8; |
| 2592 | 2609 | ||
| 2593 | assert(index == 16); | 2610 | assert(index == 16); |
| 2594 | 2611 |
src/link/MachO.zig+27-20| ... | @@ -3542,8 +3542,8 @@ pub fn requiresCodeSig(self: MachO) bool { | ... | @@ -3542,8 +3542,8 @@ pub fn requiresCodeSig(self: MachO) bool { |
| 3542 | const target = self.getTarget(); | 3542 | const target = self.getTarget(); |
| 3543 | return switch (target.cpu.arch) { | 3543 | return switch (target.cpu.arch) { |
| 3544 | .aarch64 => switch (target.os.tag) { | 3544 | .aarch64 => switch (target.os.tag) { |
| 3545 | .macos => true, | 3545 | .bridgeos, .driverkit, .macos => true, |
| 3546 | .watchos, .tvos, .ios, .visionos => target.abi == .simulator, | 3546 | .ios, .tvos, .visionos, .watchos => target.abi == .simulator, |
| 3547 | else => false, | 3547 | else => false, |
| 3548 | }, | 3548 | }, |
| 3549 | .x86_64 => false, | 3549 | .x86_64 => false, |
| ... | @@ -4172,36 +4172,38 @@ pub const Platform = struct { | ... | @@ -4172,36 +4172,38 @@ pub const Platform = struct { |
| 4172 | const cmd = lc.cast(macho.build_version_command).?; | 4172 | const cmd = lc.cast(macho.build_version_command).?; |
| 4173 | return .{ | 4173 | return .{ |
| 4174 | .os_tag = switch (cmd.platform) { | 4174 | .os_tag = switch (cmd.platform) { |
| 4175 | .MACOS => .macos, | 4175 | .BRIDGEOS => .bridgeos, |
| 4176 | .DRIVERKIT => .driverkit, | ||
| 4176 | .IOS, .IOSSIMULATOR => .ios, | 4177 | .IOS, .IOSSIMULATOR => .ios, |
| 4177 | .TVOS, .TVOSSIMULATOR => .tvos, | ||
| 4178 | .WATCHOS, .WATCHOSSIMULATOR => .watchos, | ||
| 4179 | .MACCATALYST => .ios, | 4178 | .MACCATALYST => .ios, |
| 4179 | .MACOS => .macos, | ||
| 4180 | .TVOS, .TVOSSIMULATOR => .tvos, | ||
| 4180 | .VISIONOS, .VISIONOSSIMULATOR => .visionos, | 4181 | .VISIONOS, .VISIONOSSIMULATOR => .visionos, |
| 4182 | .WATCHOS, .WATCHOSSIMULATOR => .watchos, | ||
| 4181 | else => @panic("TODO"), | 4183 | else => @panic("TODO"), |
| 4182 | }, | 4184 | }, |
| 4183 | .abi = switch (cmd.platform) { | 4185 | .abi = switch (cmd.platform) { |
| 4184 | .MACCATALYST => .macabi, | 4186 | .MACCATALYST => .macabi, |
| 4185 | .IOSSIMULATOR, | 4187 | .IOSSIMULATOR, |
| 4186 | .TVOSSIMULATOR, | 4188 | .TVOSSIMULATOR, |
| 4187 | .WATCHOSSIMULATOR, | ||
| 4188 | .VISIONOSSIMULATOR, | 4189 | .VISIONOSSIMULATOR, |
| 4190 | .WATCHOSSIMULATOR, | ||
| 4189 | => .simulator, | 4191 | => .simulator, |
| 4190 | else => .none, | 4192 | else => .none, |
| 4191 | }, | 4193 | }, |
| 4192 | .version = appleVersionToSemanticVersion(cmd.minos), | 4194 | .version = appleVersionToSemanticVersion(cmd.minos), |
| 4193 | }; | 4195 | }; |
| 4194 | }, | 4196 | }, |
| 4195 | .VERSION_MIN_MACOSX, | ||
| 4196 | .VERSION_MIN_IPHONEOS, | 4197 | .VERSION_MIN_IPHONEOS, |
| 4198 | .VERSION_MIN_MACOSX, | ||
| 4197 | .VERSION_MIN_TVOS, | 4199 | .VERSION_MIN_TVOS, |
| 4198 | .VERSION_MIN_WATCHOS, | 4200 | .VERSION_MIN_WATCHOS, |
| 4199 | => { | 4201 | => { |
| 4200 | const cmd = lc.cast(macho.version_min_command).?; | 4202 | const cmd = lc.cast(macho.version_min_command).?; |
| 4201 | return .{ | 4203 | return .{ |
| 4202 | .os_tag = switch (lc.cmd()) { | 4204 | .os_tag = switch (lc.cmd()) { |
| 4203 | .VERSION_MIN_MACOSX => .macos, | ||
| 4204 | .VERSION_MIN_IPHONEOS => .ios, | 4205 | .VERSION_MIN_IPHONEOS => .ios, |
| 4206 | .VERSION_MIN_MACOSX => .macos, | ||
| 4205 | .VERSION_MIN_TVOS => .tvos, | 4207 | .VERSION_MIN_TVOS => .tvos, |
| 4206 | .VERSION_MIN_WATCHOS => .watchos, | 4208 | .VERSION_MIN_WATCHOS => .watchos, |
| 4207 | else => unreachable, | 4209 | else => unreachable, |
| ... | @@ -4228,15 +4230,17 @@ pub const Platform = struct { | ... | @@ -4228,15 +4230,17 @@ pub const Platform = struct { |
| 4228 | 4230 | ||
| 4229 | pub fn toApplePlatform(plat: Platform) macho.PLATFORM { | 4231 | pub fn toApplePlatform(plat: Platform) macho.PLATFORM { |
| 4230 | return switch (plat.os_tag) { | 4232 | return switch (plat.os_tag) { |
| 4231 | .macos => .MACOS, | 4233 | .bridgeos => .BRIDGEOS, |
| 4234 | .driverkit => .DRIVERKIT, | ||
| 4232 | .ios => switch (plat.abi) { | 4235 | .ios => switch (plat.abi) { |
| 4233 | .simulator => .IOSSIMULATOR, | ||
| 4234 | .macabi => .MACCATALYST, | 4236 | .macabi => .MACCATALYST, |
| 4237 | .simulator => .IOSSIMULATOR, | ||
| 4235 | else => .IOS, | 4238 | else => .IOS, |
| 4236 | }, | 4239 | }, |
| 4240 | .macos => .MACOS, | ||
| 4237 | .tvos => if (plat.abi == .simulator) .TVOSSIMULATOR else .TVOS, | 4241 | .tvos => if (plat.abi == .simulator) .TVOSSIMULATOR else .TVOS, |
| 4238 | .watchos => if (plat.abi == .simulator) .WATCHOSSIMULATOR else .WATCHOS, | ||
| 4239 | .visionos => if (plat.abi == .simulator) .VISIONOSSIMULATOR else .VISIONOS, | 4242 | .visionos => if (plat.abi == .simulator) .VISIONOSSIMULATOR else .VISIONOS, |
| 4243 | .watchos => if (plat.abi == .simulator) .WATCHOSSIMULATOR else .WATCHOS, | ||
| 4240 | else => unreachable, | 4244 | else => unreachable, |
| 4241 | }; | 4245 | }; |
| 4242 | } | 4246 | } |
| ... | @@ -4305,15 +4309,18 @@ const SupportedPlatforms = struct { | ... | @@ -4305,15 +4309,18 @@ const SupportedPlatforms = struct { |
| 4305 | // Source: https://github.com/apple-oss-distributions/ld64/blob/59a99ab60399c5e6c49e6945a9e1049c42b71135/src/ld/PlatformSupport.cpp#L52 | 4309 | // Source: https://github.com/apple-oss-distributions/ld64/blob/59a99ab60399c5e6c49e6945a9e1049c42b71135/src/ld/PlatformSupport.cpp#L52 |
| 4306 | // zig fmt: off | 4310 | // zig fmt: off |
| 4307 | const supported_platforms = [_]SupportedPlatforms{ | 4311 | const supported_platforms = [_]SupportedPlatforms{ |
| 4308 | .{ .macos, .none, 0xA0E00, 0xA0800 }, | 4312 | .{ .bridgeos, .none, 0x010000, 0x010000 }, |
| 4309 | .{ .ios, .none, 0xC0000, 0x70000 }, | 4313 | .{ .driverkit, .none, 0x130000, 0x130000 }, |
| 4310 | .{ .tvos, .none, 0xC0000, 0x70000 }, | 4314 | .{ .ios, .none, 0x0C0000, 0x070000 }, |
| 4311 | .{ .watchos, .none, 0x50000, 0x20000 }, | 4315 | .{ .ios, .macabi, 0x0D0000, 0x0D0000 }, |
| 4312 | .{ .visionos, .none, 0x10000, 0x10000 }, | 4316 | .{ .ios, .simulator, 0x0D0000, 0x080000 }, |
| 4313 | .{ .ios, .simulator, 0xD0000, 0x80000 }, | 4317 | .{ .macos, .none, 0x0A0E00, 0x0A0800 }, |
| 4314 | .{ .tvos, .simulator, 0xD0000, 0x80000 }, | 4318 | .{ .tvos, .none, 0x0C0000, 0x070000 }, |
| 4315 | .{ .watchos, .simulator, 0x60000, 0x20000 }, | 4319 | .{ .tvos, .simulator, 0x0D0000, 0x080000 }, |
| 4316 | .{ .visionos, .simulator, 0x10000, 0x10000 }, | 4320 | .{ .visionos, .none, 0x010000, 0x010000 }, |
| 4321 | .{ .visionos, .simulator, 0x010000, 0x010000 }, | ||
| 4322 | .{ .watchos, .none, 0x050000, 0x020000 }, | ||
| 4323 | .{ .watchos, .simulator, 0x060000, 0x020000 }, | ||
| 4317 | }; | 4324 | }; |
| 4318 | // zig fmt: on | 4325 | // zig fmt: on |
| 4319 | 4326 |