authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-08-30 12:08:18-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-21 14:09:14-07:00
logf58200e3f2967a06f343c9fc9dcae9de18def92a
tree84257e40a7a0186fbc10cf7467e65f004036d3e3
parent2a97e0af6d42e038d962890a320e262e676d44cb

Elf2: create a new linker from scratch

This iteration already has significantly better incremental support. Closes #24110

45 files changed, 4141 insertions(+), 536 deletions(-)

CMakeLists.txt+2
...@@ -583,6 +583,7 @@ set(ZIG_STAGE2_SOURCES...@@ -583,6 +583,7 @@ set(ZIG_STAGE2_SOURCES
583 src/link/Elf/relocatable.zig583 src/link/Elf/relocatable.zig
584 src/link/Elf/relocation.zig584 src/link/Elf/relocation.zig
585 src/link/Elf/synthetic_sections.zig585 src/link/Elf/synthetic_sections.zig
586 src/link/Elf2.zig
586 src/link/Goff.zig587 src/link/Goff.zig
587 src/link/LdScript.zig588 src/link/LdScript.zig
588 src/link/Lld.zig589 src/link/Lld.zig
...@@ -612,6 +613,7 @@ set(ZIG_STAGE2_SOURCES...@@ -612,6 +613,7 @@ set(ZIG_STAGE2_SOURCES
612 src/link/MachO/synthetic.zig613 src/link/MachO/synthetic.zig
613 src/link/MachO/Thunk.zig614 src/link/MachO/Thunk.zig
614 src/link/MachO/uuid.zig615 src/link/MachO/uuid.zig
616 src/link/MappedFile.zig
615 src/link/Queue.zig617 src/link/Queue.zig
616 src/link/StringTable.zig618 src/link/StringTable.zig
617 src/link/Wasm.zig619 src/link/Wasm.zig
build.zig+1
...@@ -202,6 +202,7 @@ pub fn build(b: *std.Build) !void {...@@ -202,6 +202,7 @@ pub fn build(b: *std.Build) !void {
202 });202 });
203 exe.pie = pie;203 exe.pie = pie;
204 exe.entitlements = entitlements;204 exe.entitlements = entitlements;
205 exe.use_new_linker = b.option(bool, "new-linker", "Use the new linker");
205206
206 const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend");207 const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend");
207 exe.use_llvm = use_llvm;208 exe.use_llvm = use_llvm;
ci/x86_64-linux-debug-llvm.sh created100644→100755
lib/compiler_rt/fma.zig+4-4
...@@ -203,7 +203,7 @@ fn add_adjusted(a: f64, b: f64) f64 {...@@ -203,7 +203,7 @@ fn add_adjusted(a: f64, b: f64) f64 {
203 if (uhii & 1 == 0) {203 if (uhii & 1 == 0) {
204 // hibits += copysign(1.0, sum.hi, sum.lo)204 // hibits += copysign(1.0, sum.hi, sum.lo)
205 const uloi: u64 = @bitCast(sum.lo);205 const uloi: u64 = @bitCast(sum.lo);
206 uhii += 1 - ((uhii ^ uloi) >> 62);206 uhii = uhii + 1 - ((uhii ^ uloi) >> 62);
207 sum.hi = @bitCast(uhii);207 sum.hi = @bitCast(uhii);
208 }208 }
209 }209 }
...@@ -217,7 +217,7 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) f64 {...@@ -217,7 +217,7 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) f64 {
217 const bits_lost = -@as(i32, @intCast((uhii >> 52) & 0x7FF)) - scale + 1;217 const bits_lost = -@as(i32, @intCast((uhii >> 52) & 0x7FF)) - scale + 1;
218 if ((bits_lost != 1) == (uhii & 1 != 0)) {218 if ((bits_lost != 1) == (uhii & 1 != 0)) {
219 const uloi: u64 = @bitCast(sum.lo);219 const uloi: u64 = @bitCast(sum.lo);
220 uhii += 1 - (((uhii ^ uloi) >> 62) & 2);220 uhii = uhii + 1 - (((uhii ^ uloi) >> 62) & 2);
221 sum.hi = @bitCast(uhii);221 sum.hi = @bitCast(uhii);
222 }222 }
223 }223 }
...@@ -259,7 +259,7 @@ fn add_adjusted128(a: f128, b: f128) f128 {...@@ -259,7 +259,7 @@ fn add_adjusted128(a: f128, b: f128) f128 {
259 if (uhii & 1 == 0) {259 if (uhii & 1 == 0) {
260 // hibits += copysign(1.0, sum.hi, sum.lo)260 // hibits += copysign(1.0, sum.hi, sum.lo)
261 const uloi: u128 = @bitCast(sum.lo);261 const uloi: u128 = @bitCast(sum.lo);
262 uhii += 1 - ((uhii ^ uloi) >> 126);262 uhii = uhii + 1 - ((uhii ^ uloi) >> 126);
263 sum.hi = @bitCast(uhii);263 sum.hi = @bitCast(uhii);
264 }264 }
265 }265 }
...@@ -284,7 +284,7 @@ fn add_and_denorm128(a: f128, b: f128, scale: i32) f128 {...@@ -284,7 +284,7 @@ fn add_and_denorm128(a: f128, b: f128, scale: i32) f128 {
284 const bits_lost = -@as(i32, @intCast((uhii >> 112) & 0x7FFF)) - scale + 1;284 const bits_lost = -@as(i32, @intCast((uhii >> 112) & 0x7FFF)) - scale + 1;
285 if ((bits_lost != 1) == (uhii & 1 != 0)) {285 if ((bits_lost != 1) == (uhii & 1 != 0)) {
286 const uloi: u128 = @bitCast(sum.lo);286 const uloi: u128 = @bitCast(sum.lo);
287 uhii += 1 - (((uhii ^ uloi) >> 126) & 2);287 uhii = uhii + 1 - (((uhii ^ uloi) >> 126) & 2);
288 sum.hi = @bitCast(uhii);288 sum.hi = @bitCast(uhii);
289 }289 }
290 }290 }
lib/std/Build/Step/Compile.zig+3
...@@ -192,6 +192,7 @@ want_lto: ?bool = null,...@@ -192,6 +192,7 @@ want_lto: ?bool = null,
192192
193use_llvm: ?bool,193use_llvm: ?bool,
194use_lld: ?bool,194use_lld: ?bool,
195use_new_linker: ?bool,
195196
196/// Corresponds to the `-fallow-so-scripts` / `-fno-allow-so-scripts` CLI197/// Corresponds to the `-fallow-so-scripts` / `-fno-allow-so-scripts` CLI
197/// flags, overriding the global user setting provided to the `zig build`198/// flags, overriding the global user setting provided to the `zig build`
...@@ -441,6 +442,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile {...@@ -441,6 +442,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
441442
442 .use_llvm = options.use_llvm,443 .use_llvm = options.use_llvm,
443 .use_lld = options.use_lld,444 .use_lld = options.use_lld,
445 .use_new_linker = null,
444446
445 .zig_process = null,447 .zig_process = null,
446 };448 };
...@@ -1096,6 +1098,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {...@@ -1096,6 +1098,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
10961098
1097 try addFlag(&zig_args, "llvm", compile.use_llvm);1099 try addFlag(&zig_args, "llvm", compile.use_llvm);
1098 try addFlag(&zig_args, "lld", compile.use_lld);1100 try addFlag(&zig_args, "lld", compile.use_lld);
1101 try addFlag(&zig_args, "new-linker", compile.use_new_linker);
10991102
1100 if (compile.root_module.resolved_target.?.query.ofmt) |ofmt| {1103 if (compile.root_module.resolved_target.?.query.ofmt) |ofmt| {
1101 try zig_args.append(try std.fmt.allocPrint(arena, "-ofmt={s}", .{@tagName(ofmt)}));1104 try zig_args.append(try std.fmt.allocPrint(arena, "-ofmt={s}", .{@tagName(ofmt)}));
lib/std/elf.zig+493-102
...@@ -323,6 +323,8 @@ pub const PT_LOPROC = 0x70000000;...@@ -323,6 +323,8 @@ pub const PT_LOPROC = 0x70000000;
323/// End of processor-specific323/// End of processor-specific
324pub const PT_HIPROC = 0x7fffffff;324pub const PT_HIPROC = 0x7fffffff;
325325
326pub const PN_XNUM = 0xffff;
327
326/// Section header table entry unused328/// Section header table entry unused
327pub const SHT_NULL = 0;329pub const SHT_NULL = 0;
328/// Program data330/// Program data
...@@ -385,63 +387,149 @@ pub const SHT_HIUSER = 0xffffffff;...@@ -385,63 +387,149 @@ pub const SHT_HIUSER = 0xffffffff;
385// Note type for .note.gnu.build_id387// Note type for .note.gnu.build_id
386pub const NT_GNU_BUILD_ID = 3;388pub const NT_GNU_BUILD_ID = 3;
387389
388/// Local symbol390/// Deprecated, use `@intFromEnum(std.elf.STB.LOCAL)`
389pub const STB_LOCAL = 0;391pub const STB_LOCAL = @intFromEnum(STB.LOCAL);
390/// Global symbol392/// Deprecated, use `@intFromEnum(std.elf.STB.GLOBAL)`
391pub const STB_GLOBAL = 1;393pub const STB_GLOBAL = @intFromEnum(STB.GLOBAL);
392/// Weak symbol394/// Deprecated, use `@intFromEnum(std.elf.STB.WEAK)`
393pub const STB_WEAK = 2;395pub const STB_WEAK = @intFromEnum(STB.WEAK);
394/// Number of defined types396/// Deprecated, use `std.elf.STB.NUM`
395pub const STB_NUM = 3;397pub const STB_NUM = STB.NUM;
396/// Start of OS-specific398/// Deprecated, use `@intFromEnum(std.elf.STB.LOOS)`
397pub const STB_LOOS = 10;399pub const STB_LOOS = @intFromEnum(STB.LOOS);
398/// Unique symbol400/// Deprecated, use `@intFromEnum(std.elf.STB.GNU_UNIQUE)`
399pub const STB_GNU_UNIQUE = 10;401pub const STB_GNU_UNIQUE = @intFromEnum(STB.GNU_UNIQUE);
400/// End of OS-specific402/// Deprecated, use `@intFromEnum(std.elf.STB.HIOS)`
401pub const STB_HIOS = 12;403pub const STB_HIOS = @intFromEnum(STB.HIOS);
402/// Start of processor-specific404/// Deprecated, use `@intFromEnum(std.elf.STB.LOPROC)`
403pub const STB_LOPROC = 13;405pub const STB_LOPROC = @intFromEnum(STB.LOPROC);
404/// End of processor-specific406/// Deprecated, use `@intFromEnum(std.elf.STB.HIPROC)`
405pub const STB_HIPROC = 15;407pub const STB_HIPROC = @intFromEnum(STB.HIPROC);
406408
407pub const STB_MIPS_SPLIT_COMMON = 13;409/// Deprecated, use `@intFromEnum(std.elf.STB.MIPS_SPLIT_COMMON)`
408410pub const STB_MIPS_SPLIT_COMMON = @intFromEnum(STB.MIBS_SPLIT_COMMON);
409/// Symbol type is unspecified411
410pub const STT_NOTYPE = 0;412/// Deprecated, use `@intFromEnum(std.elf.STT.NOTYPE)`
411/// Symbol is a data object413pub const STT_NOTYPE = @intFromEnum(STT.NOTYPE);
412pub const STT_OBJECT = 1;414/// Deprecated, use `@intFromEnum(std.elf.STT.OBJECT)`
413/// Symbol is a code object415pub const STT_OBJECT = @intFromEnum(STT.OBJECT);
414pub const STT_FUNC = 2;416/// Deprecated, use `@intFromEnum(std.elf.STT.FUNC)`
415/// Symbol associated with a section417pub const STT_FUNC = @intFromEnum(STT.FUNC);
416pub const STT_SECTION = 3;418/// Deprecated, use `@intFromEnum(std.elf.STT.SECTION)`
417/// Symbol's name is file name419pub const STT_SECTION = @intFromEnum(STT.SECTION);
418pub const STT_FILE = 4;420/// Deprecated, use `@intFromEnum(std.elf.STT.FILE)`
419/// Symbol is a common data object421pub const STT_FILE = @intFromEnum(STT.FILE);
420pub const STT_COMMON = 5;422/// Deprecated, use `@intFromEnum(std.elf.STT.COMMON)`
421/// Symbol is thread-local data object423pub const STT_COMMON = @intFromEnum(STT.COMMON);
422pub const STT_TLS = 6;424/// Deprecated, use `@intFromEnum(std.elf.STT.TLS)`
423/// Number of defined types425pub const STT_TLS = @intFromEnum(STT.TLS);
424pub const STT_NUM = 7;426/// Deprecated, use `std.elf.STT.NUM`
425/// Start of OS-specific427pub const STT_NUM = STT.NUM;
426pub const STT_LOOS = 10;428/// Deprecated, use `@intFromEnum(std.elf.STT.LOOS)`
427/// Symbol is indirect code object429pub const STT_LOOS = @intFromEnum(STT.LOOS);
428pub const STT_GNU_IFUNC = 10;430/// Deprecated, use `@intFromEnum(std.elf.STT.GNU_IFUNC)`
429/// End of OS-specific431pub const STT_GNU_IFUNC = @intFromEnum(STT.GNU_IFUNC);
430pub const STT_HIOS = 12;432/// Deprecated, use `@intFromEnum(std.elf.STT.HIOS)`
431/// Start of processor-specific433pub const STT_HIOS = @intFromEnum(STT.HIOS);
432pub const STT_LOPROC = 13;434/// Deprecated, use `@intFromEnum(std.elf.STT.LOPROC)`
433/// End of processor-specific435pub const STT_LOPROC = @intFromEnum(STT.LOPROC);
434pub const STT_HIPROC = 15;436/// Deprecated, use `@intFromEnum(std.elf.STT.HIPROC)`
437pub const STT_HIPROC = @intFromEnum(STT.HIPROC);
438
439/// Deprecated, use `@intFromEnum(std.elf.STT.SPARC_REGISTER)`
440pub const STT_SPARC_REGISTER = @intFromEnum(STT.SPARC_REGISTER);
441
442/// Deprecated, use `@intFromEnum(std.elf.STT.PARISC_MILLICODE)`
443pub const STT_PARISC_MILLICODE = @intFromEnum(STT.PARISC_MILLICODE);
444
445/// Deprecated, use `@intFromEnum(std.elf.STT.HP_OPAQUE)`
446pub const STT_HP_OPAQUE = @intFromEnum(STT.HP_OPAQUE);
447/// Deprecated, use `@intFromEnum(std.elf.STT.HP_STUB)`
448pub const STT_HP_STUB = @intFromEnum(STT.HP_STUB);
449
450/// Deprecated, use `@intFromEnum(std.elf.STT.ARM_TFUNC)`
451pub const STT_ARM_TFUNC = @intFromEnum(STT.ARM_TFUNC);
452/// Deprecated, use `@intFromEnum(std.elf.STT.ARM_16BIT)`
453pub const STT_ARM_16BIT = @intFromEnum(STT.ARM_16BIT);
454
455pub const STB = enum(u4) {
456 /// Local symbol
457 LOCAL = 0,
458 /// Global symbol
459 GLOBAL = 1,
460 /// Weak symbol
461 WEAK = 2,
462 _,
463
464 /// Number of defined types
465 pub const NUM = @typeInfo(STB).@"enum".fields.len;
466
467 /// Start of OS-specific
468 pub const LOOS: STB = @enumFromInt(10);
469 /// End of OS-specific
470 pub const HIOS: STB = @enumFromInt(12);
471
472 /// Unique symbol
473 pub const GNU_UNIQUE: STB = @enumFromInt(@intFromEnum(LOOS) + 0);
474
475 /// Start of processor-specific
476 pub const LOPROC: STB = @enumFromInt(13);
477 /// End of processor-specific
478 pub const HIPROC: STB = @enumFromInt(15);
479
480 pub const MIPS_SPLIT_COMMON: STB = @enumFromInt(@intFromEnum(LOPROC) + 0);
481};
482
483pub const STT = enum(u4) {
484 /// Symbol type is unspecified
485 NOTYPE = 0,
486 /// Symbol is a data object
487 OBJECT = 1,
488 /// Symbol is a code object
489 FUNC = 2,
490 /// Symbol associated with a section
491 SECTION = 3,
492 /// Symbol's name is file name
493 FILE = 4,
494 /// Symbol is a common data object
495 COMMON = 5,
496 /// Symbol is thread-local data object
497 TLS = 6,
498 _,
499
500 /// Number of defined types
501 pub const NUM = @typeInfo(STT).@"enum".fields.len;
502
503 /// Start of OS-specific
504 pub const LOOS: STT = @enumFromInt(10);
505 /// End of OS-specific
506 pub const HIOS: STT = @enumFromInt(12);
435507
436pub const STT_SPARC_REGISTER = 13;508 /// Symbol is indirect code object
509 pub const GNU_IFUNC: STT = @enumFromInt(@intFromEnum(LOOS) + 0);
437510
438pub const STT_PARISC_MILLICODE = 13;511 pub const HP_OPAQUE: STT = @enumFromInt(@intFromEnum(LOOS) + 1);
512 pub const HP_STUB: STT = @enumFromInt(@intFromEnum(LOOS) + 2);
439513
440pub const STT_HP_OPAQUE = (STT_LOOS + 0x1);514 /// Start of processor-specific
441pub const STT_HP_STUB = (STT_LOOS + 0x2);515 pub const LOPROC: STT = @enumFromInt(13);
516 /// End of processor-specific
517 pub const HIPROC: STT = @enumFromInt(15);
442518
443pub const STT_ARM_TFUNC = STT_LOPROC;519 pub const SPARC_REGISTER: STT = @enumFromInt(@intFromEnum(LOPROC) + 0);
444pub const STT_ARM_16BIT = STT_HIPROC;520
521 pub const PARISC_MILLICODE: STT = @enumFromInt(@intFromEnum(LOPROC) + 0);
522
523 pub const ARM_TFUNC: STT = @enumFromInt(@intFromEnum(LOPROC) + 0);
524 pub const ARM_16BIT: STT = @enumFromInt(@intFromEnum(HIPROC) + 2);
525};
526
527pub const STV = enum(u3) {
528 DEFAULT = 0,
529 INTERNAL = 1,
530 HIDDEN = 2,
531 PROTECTED = 3,
532};
445533
446pub const MAGIC = "\x7fELF";534pub const MAGIC = "\x7fELF";
447535
...@@ -534,15 +622,15 @@ pub const Header = struct {...@@ -534,15 +622,15 @@ pub const Header = struct {
534 const buf = try r.peek(@sizeOf(Elf64_Ehdr));622 const buf = try r.peek(@sizeOf(Elf64_Ehdr));
535623
536 if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic;624 if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic;
537 if (buf[EI_VERSION] != 1) return error.InvalidElfVersion;625 if (buf[EI.VERSION] != 1) return error.InvalidElfVersion;
538626
539 const endian: std.builtin.Endian = switch (buf[EI_DATA]) {627 const endian: std.builtin.Endian = switch (buf[EI.DATA]) {
540 ELFDATA2LSB => .little,628 ELFDATA2LSB => .little,
541 ELFDATA2MSB => .big,629 ELFDATA2MSB => .big,
542 else => return error.InvalidElfEndian,630 else => return error.InvalidElfEndian,
543 };631 };
544632
545 return switch (buf[EI_CLASS]) {633 return switch (buf[EI.CLASS]) {
546 ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian),634 ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian),
547 ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian),635 ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian),
548 else => return error.InvalidElfClass,636 else => return error.InvalidElfClass,
...@@ -559,8 +647,8 @@ pub const Header = struct {...@@ -559,8 +647,8 @@ pub const Header = struct {
559 else => @compileError("bad type"),647 else => @compileError("bad type"),
560 },648 },
561 .endian = endian,649 .endian = endian,
562 .os_abi = @enumFromInt(hdr.e_ident[EI_OSABI]),650 .os_abi = @enumFromInt(hdr.e_ident[EI.OSABI]),
563 .abi_version = hdr.e_ident[EI_ABIVERSION],651 .abi_version = hdr.e_ident[EI.ABIVERSION],
564 .type = hdr.e_type,652 .type = hdr.e_type,
565 .machine = hdr.e_machine,653 .machine = hdr.e_machine,
566 .entry = hdr.e_entry,654 .entry = hdr.e_entry,
...@@ -683,38 +771,200 @@ fn takeShdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Shdr {...@@ -683,38 +771,200 @@ fn takeShdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Shdr {
683 };771 };
684}772}
685773
686pub const ELFCLASSNONE = 0;774pub const EI = struct {
687pub const ELFCLASS32 = 1;775 pub const CLASS = 4;
688pub const ELFCLASS64 = 2;776 pub const DATA = 5;
689pub const ELFCLASSNUM = 3;777 pub const VERSION = 6;
690778 pub const OSABI = 7;
691pub const ELFDATANONE = 0;779 pub const ABIVERSION = 8;
692pub const ELFDATA2LSB = 1;780 pub const PAD = 9;
693pub const ELFDATA2MSB = 2;781 pub const NIDENT = 16;
694pub const ELFDATANUM = 3;782};
695783
696pub const EI_CLASS = 4;784/// Deprecated, use `std.elf.EI.CLASS`
697pub const EI_DATA = 5;785pub const EI_CLASS = EI.CLASS;
698pub const EI_VERSION = 6;786/// Deprecated, use `std.elf.EI.DATA`
699pub const EI_OSABI = 7;787pub const EI_DATA = EI.DATA;
700pub const EI_ABIVERSION = 8;788/// Deprecated, use `std.elf.EI.VERSION`
701pub const EI_PAD = 9;789pub const EI_VERSION = EI.VERSION;
702790/// Deprecated, use `std.elf.EI.OSABI`
703pub const EI_NIDENT = 16;791pub const EI_OSABI = EI.OSABI;
792/// Deprecated, use `std.elf.EI.ABIVERSION`
793pub const EI_ABIVERSION = EI.ABIVERSION;
794/// Deprecated, use `std.elf.EI.PAD`
795pub const EI_PAD = EI.PAD;
796/// Deprecated, use `std.elf.EI.NIDENT`
797pub const EI_NIDENT = EI.NIDENT;
704798
705pub const Half = u16;799pub const Half = u16;
706pub const Word = u32;800pub const Word = u32;
707pub const Sword = i32;801pub const Sword = i32;
708pub const Elf32_Xword = u64;802pub const Xword = u64;
709pub const Elf32_Sxword = i64;803pub const Sxword = i64;
710pub const Elf64_Xword = u64;804pub const Section = u16;
805pub const Elf32 = struct {
806 pub const Addr = u32;
807 pub const Off = u32;
808 pub const Ehdr = extern struct {
809 ident: [EI.NIDENT]u8,
810 type: ET,
811 machine: EM,
812 version: Word,
813 entry: Elf32.Addr,
814 phoff: Elf32.Off,
815 shoff: Elf32.Off,
816 flags: Word,
817 ehsize: Half,
818 phentsize: Half,
819 phnum: Half,
820 shentsize: Half,
821 shnum: Half,
822 shstrndx: Half,
823 };
824 pub const Phdr = extern struct {
825 type: Word,
826 offset: Elf32.Off,
827 vaddr: Elf32.Addr,
828 paddr: Elf32.Addr,
829 filesz: Word,
830 memsz: Word,
831 flags: PF,
832 @"align": Word,
833 };
834 pub const Shdr = extern struct {
835 name: Word,
836 type: Word,
837 flags: packed struct { shf: SHF },
838 addr: Elf32.Addr,
839 offset: Elf32.Off,
840 size: Word,
841 link: Word,
842 info: Word,
843 addralign: Word,
844 entsize: Word,
845 };
846 pub const Chdr = extern struct {
847 type: COMPRESS,
848 size: Word,
849 addralign: Word,
850 };
851 pub const Sym = extern struct {
852 name: Word,
853 value: Elf32.Addr,
854 size: Word,
855 info: Info,
856 other: Other,
857 shndx: Section,
858
859 pub const Info = packed struct(u8) {
860 type: STT,
861 bind: STB,
862 };
863
864 pub const Other = packed struct(u8) {
865 visibility: STV,
866 unused: u5 = 0,
867 };
868 };
869 comptime {
870 assert(@sizeOf(Elf32.Ehdr) == 52);
871 assert(@sizeOf(Elf32.Phdr) == 32);
872 assert(@sizeOf(Elf32.Shdr) == 40);
873 assert(@sizeOf(Elf32.Sym) == 16);
874 }
875};
876pub const Elf64 = struct {
877 pub const Addr = u64;
878 pub const Off = u64;
879 pub const Ehdr = extern struct {
880 ident: [EI.NIDENT]u8,
881 type: ET,
882 machine: EM,
883 version: Word,
884 entry: Elf64.Addr,
885 phoff: Elf64.Off,
886 shoff: Elf64.Off,
887 flags: Word,
888 ehsize: Half,
889 phentsize: Half,
890 phnum: Half,
891 shentsize: Half,
892 shnum: Half,
893 shstrndx: Half,
894 };
895 pub const Phdr = extern struct {
896 type: Word,
897 flags: PF,
898 offset: Elf64.Off,
899 vaddr: Elf64.Addr,
900 paddr: Elf64.Addr,
901 filesz: Xword,
902 memsz: Xword,
903 @"align": Xword,
904 };
905 pub const Shdr = extern struct {
906 name: Word,
907 type: Word,
908 flags: packed struct { shf: SHF, unused: Word = 0 },
909 addr: Elf64.Addr,
910 offset: Elf64.Off,
911 size: Xword,
912 link: Word,
913 info: Word,
914 addralign: Xword,
915 entsize: Xword,
916 };
917 pub const Chdr = extern struct {
918 type: COMPRESS,
919 reserved: Word = 0,
920 size: Xword,
921 addralign: Xword,
922 };
923 pub const Sym = extern struct {
924 name: Word,
925 info: Info,
926 other: Other,
927 shndx: Section,
928 value: Elf64.Addr,
929 size: Xword,
930
931 pub const Info = Elf32.Sym.Info;
932 pub const Other = Elf32.Sym.Other;
933 };
934 comptime {
935 assert(@sizeOf(Elf64.Ehdr) == 64);
936 assert(@sizeOf(Elf64.Phdr) == 56);
937 assert(@sizeOf(Elf64.Shdr) == 64);
938 assert(@sizeOf(Elf64.Sym) == 24);
939 }
940};
941pub const ElfN = switch (@sizeOf(usize)) {
942 4 => Elf32,
943 8 => Elf64,
944 else => @compileError("expected pointer size of 32 or 64"),
945};
946
947/// Deprecated, use `std.elf.Xword`
948pub const Elf32_Xword = Xword;
949/// Deprecated, use `std.elf.Sxword`
950pub const Elf32_Sxword = Sxword;
951/// Deprecated, use `std.elf.Xword`
952pub const Elf64_Xword = Xword;
953/// Deprecated, use `std.elf.Sxword`
711pub const Elf64_Sxword = i64;954pub const Elf64_Sxword = i64;
955/// Deprecated, use `std.elf.Elf32.Addr`
712pub const Elf32_Addr = u32;956pub const Elf32_Addr = u32;
957/// Deprecated, use `std.elf.Elf64.Addr`
713pub const Elf64_Addr = u64;958pub const Elf64_Addr = u64;
959/// Deprecated, use `std.elf.Elf32.Off`
714pub const Elf32_Off = u32;960pub const Elf32_Off = u32;
961/// Deprecated, use `std.elf.Elf64.Off`
715pub const Elf64_Off = u64;962pub const Elf64_Off = u64;
963/// Deprecated, use `std.elf.Section`
716pub const Elf32_Section = u16;964pub const Elf32_Section = u16;
965/// Deprecated, use `std.elf.Section`
717pub const Elf64_Section = u16;966pub const Elf64_Section = u16;
967/// Deprecated, use `std.elf.Elf32.Ehdr`
718pub const Elf32_Ehdr = extern struct {968pub const Elf32_Ehdr = extern struct {
719 e_ident: [EI_NIDENT]u8,969 e_ident: [EI_NIDENT]u8,
720 e_type: ET,970 e_type: ET,
...@@ -731,8 +981,9 @@ pub const Elf32_Ehdr = extern struct {...@@ -731,8 +981,9 @@ pub const Elf32_Ehdr = extern struct {
731 e_shnum: Half,981 e_shnum: Half,
732 e_shstrndx: Half,982 e_shstrndx: Half,
733};983};
984/// Deprecated, use `std.elf.Elf64.Ehdr`
734pub const Elf64_Ehdr = extern struct {985pub const Elf64_Ehdr = extern struct {
735 e_ident: [EI_NIDENT]u8,986 e_ident: [EI.NIDENT]u8,
736 e_type: ET,987 e_type: ET,
737 e_machine: EM,988 e_machine: EM,
738 e_version: Word,989 e_version: Word,
...@@ -747,6 +998,7 @@ pub const Elf64_Ehdr = extern struct {...@@ -747,6 +998,7 @@ pub const Elf64_Ehdr = extern struct {
747 e_shnum: Half,998 e_shnum: Half,
748 e_shstrndx: Half,999 e_shstrndx: Half,
749};1000};
1001/// Deprecated, use `std.elf.Elf32.Phdr`
750pub const Elf32_Phdr = extern struct {1002pub const Elf32_Phdr = extern struct {
751 p_type: Word,1003 p_type: Word,
752 p_offset: Elf32_Off,1004 p_offset: Elf32_Off,
...@@ -757,6 +1009,7 @@ pub const Elf32_Phdr = extern struct {...@@ -757,6 +1009,7 @@ pub const Elf32_Phdr = extern struct {
757 p_flags: Word,1009 p_flags: Word,
758 p_align: Word,1010 p_align: Word,
759};1011};
1012/// Deprecated, use `std.elf.Elf64.Phdr`
760pub const Elf64_Phdr = extern struct {1013pub const Elf64_Phdr = extern struct {
761 p_type: Word,1014 p_type: Word,
762 p_flags: Word,1015 p_flags: Word,
...@@ -767,6 +1020,7 @@ pub const Elf64_Phdr = extern struct {...@@ -767,6 +1020,7 @@ pub const Elf64_Phdr = extern struct {
767 p_memsz: Elf64_Xword,1020 p_memsz: Elf64_Xword,
768 p_align: Elf64_Xword,1021 p_align: Elf64_Xword,
769};1022};
1023/// Deprecated, use `std.elf.Elf32.Shdr`
770pub const Elf32_Shdr = extern struct {1024pub const Elf32_Shdr = extern struct {
771 sh_name: Word,1025 sh_name: Word,
772 sh_type: Word,1026 sh_type: Word,
...@@ -779,6 +1033,7 @@ pub const Elf32_Shdr = extern struct {...@@ -779,6 +1033,7 @@ pub const Elf32_Shdr = extern struct {
779 sh_addralign: Word,1033 sh_addralign: Word,
780 sh_entsize: Word,1034 sh_entsize: Word,
781};1035};
1036/// Deprecated, use `std.elf.Elf64.Shdr`
782pub const Elf64_Shdr = extern struct {1037pub const Elf64_Shdr = extern struct {
783 sh_name: Word,1038 sh_name: Word,
784 sh_type: Word,1039 sh_type: Word,
...@@ -791,17 +1046,20 @@ pub const Elf64_Shdr = extern struct {...@@ -791,17 +1046,20 @@ pub const Elf64_Shdr = extern struct {
791 sh_addralign: Elf64_Xword,1046 sh_addralign: Elf64_Xword,
792 sh_entsize: Elf64_Xword,1047 sh_entsize: Elf64_Xword,
793};1048};
1049/// Deprecated, use `std.elf.Elf32.Chdr`
794pub const Elf32_Chdr = extern struct {1050pub const Elf32_Chdr = extern struct {
795 ch_type: COMPRESS,1051 ch_type: COMPRESS,
796 ch_size: Word,1052 ch_size: Word,
797 ch_addralign: Word,1053 ch_addralign: Word,
798};1054};
1055/// Deprecated, use `std.elf.Elf64.Chdr`
799pub const Elf64_Chdr = extern struct {1056pub const Elf64_Chdr = extern struct {
800 ch_type: COMPRESS,1057 ch_type: COMPRESS,
801 ch_reserved: Word = 0,1058 ch_reserved: Word = 0,
802 ch_size: Elf64_Xword,1059 ch_size: Elf64_Xword,
803 ch_addralign: Elf64_Xword,1060 ch_addralign: Elf64_Xword,
804};1061};
1062/// Deprecated, use `std.elf.Elf32.Sym`
805pub const Elf32_Sym = extern struct {1063pub const Elf32_Sym = extern struct {
806 st_name: Word,1064 st_name: Word,
807 st_value: Elf32_Addr,1065 st_value: Elf32_Addr,
...@@ -817,6 +1075,7 @@ pub const Elf32_Sym = extern struct {...@@ -817,6 +1075,7 @@ pub const Elf32_Sym = extern struct {
817 return @truncate(self.st_info >> 4);1075 return @truncate(self.st_info >> 4);
818 }1076 }
819};1077};
1078/// Deprecated, use `std.elf.Elf64.Sym`
820pub const Elf64_Sym = extern struct {1079pub const Elf64_Sym = extern struct {
821 st_name: Word,1080 st_name: Word,
822 st_info: u8,1081 st_info: u8,
...@@ -1020,27 +1279,18 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct {...@@ -1020,27 +1279,18 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct {
1020 flags2: Word,1279 flags2: Word,
1021};1280};
10221281
1023comptime {
1024 assert(@sizeOf(Elf32_Ehdr) == 52);
1025 assert(@sizeOf(Elf64_Ehdr) == 64);
1026
1027 assert(@sizeOf(Elf32_Phdr) == 32);
1028 assert(@sizeOf(Elf64_Phdr) == 56);
1029
1030 assert(@sizeOf(Elf32_Shdr) == 40);
1031 assert(@sizeOf(Elf64_Shdr) == 64);
1032}
1033
1034pub const Auxv = switch (@sizeOf(usize)) {1282pub const Auxv = switch (@sizeOf(usize)) {
1035 4 => Elf32_auxv_t,1283 4 => Elf32_auxv_t,
1036 8 => Elf64_auxv_t,1284 8 => Elf64_auxv_t,
1037 else => @compileError("expected pointer size of 32 or 64"),1285 else => @compileError("expected pointer size of 32 or 64"),
1038};1286};
1287/// Deprecated, use `std.elf.ElfN.Ehdr`
1039pub const Ehdr = switch (@sizeOf(usize)) {1288pub const Ehdr = switch (@sizeOf(usize)) {
1040 4 => Elf32_Ehdr,1289 4 => Elf32_Ehdr,
1041 8 => Elf64_Ehdr,1290 8 => Elf64_Ehdr,
1042 else => @compileError("expected pointer size of 32 or 64"),1291 else => @compileError("expected pointer size of 32 or 64"),
1043};1292};
1293/// Deprecated, use `std.elf.ElfN.Phdr`
1044pub const Phdr = switch (@sizeOf(usize)) {1294pub const Phdr = switch (@sizeOf(usize)) {
1045 4 => Elf32_Phdr,1295 4 => Elf32_Phdr,
1046 8 => Elf64_Phdr,1296 8 => Elf64_Phdr,
...@@ -1071,20 +1321,53 @@ pub const Shdr = switch (@sizeOf(usize)) {...@@ -1071,20 +1321,53 @@ pub const Shdr = switch (@sizeOf(usize)) {
1071 8 => Elf64_Shdr,1321 8 => Elf64_Shdr,
1072 else => @compileError("expected pointer size of 32 or 64"),1322 else => @compileError("expected pointer size of 32 or 64"),
1073};1323};
1324/// Deprecated, use `std.elf.ElfN.Chdr`
1074pub const Chdr = switch (@sizeOf(usize)) {1325pub const Chdr = switch (@sizeOf(usize)) {
1075 4 => Elf32_Chdr,1326 4 => Elf32_Chdr,
1076 8 => Elf64_Chdr,1327 8 => Elf64_Chdr,
1077 else => @compileError("expected pointer size of 32 or 64"),1328 else => @compileError("expected pointer size of 32 or 64"),
1078};1329};
1330/// Deprecated, use `std.elf.ElfN.Sym`
1079pub const Sym = switch (@sizeOf(usize)) {1331pub const Sym = switch (@sizeOf(usize)) {
1080 4 => Elf32_Sym,1332 4 => Elf32_Sym,
1081 8 => Elf64_Sym,1333 8 => Elf64_Sym,
1082 else => @compileError("expected pointer size of 32 or 64"),1334 else => @compileError("expected pointer size of 32 or 64"),
1083};1335};
1084pub const Addr = switch (@sizeOf(usize)) {1336/// Deprecated, use `std.elf.ElfN.Addr`
1085 4 => Elf32_Addr,1337pub const Addr = ElfN.Addr;
1086 8 => Elf64_Addr,1338
1087 else => @compileError("expected pointer size of 32 or 64"),1339/// Deprecated, use `@intFromEnum(std.elf.CLASS.NONE)`
1340pub const ELFCLASSNONE = @intFromEnum(CLASS.NONE);
1341/// Deprecated, use `@intFromEnum(std.elf.CLASS.@"32")`
1342pub const ELFCLASS32 = @intFromEnum(CLASS.@"32");
1343/// Deprecated, use `@intFromEnum(std.elf.CLASS.@"64")`
1344pub const ELFCLASS64 = @intFromEnum(CLASS.@"64");
1345/// Deprecated, use `@intFromEnum(std.elf.CLASS.NUM)`
1346pub const ELFCLASSNUM = CLASS.NUM;
1347pub const CLASS = enum(u8) {
1348 NONE = 0,
1349 @"32" = 1,
1350 @"64" = 2,
1351 _,
1352
1353 pub const NUM = @typeInfo(CLASS).@"enum".fields.len;
1354};
1355
1356/// Deprecated, use `@intFromEnum(std.elf.DATA.NONE)`
1357pub const ELFDATANONE = @intFromEnum(DATA.NONE);
1358/// Deprecated, use `@intFromEnum(std.elf.DATA.@"2LSB")`
1359pub const ELFDATA2LSB = @intFromEnum(DATA.@"2LSB");
1360/// Deprecated, use `@intFromEnum(std.elf.DATA.@"2MSB")`
1361pub const ELFDATA2MSB = @intFromEnum(DATA.@"2MSB");
1362/// Deprecated, use `@intFromEnum(std.elf.DATA.NUM)`
1363pub const ELFDATANUM = DATA.NUM;
1364pub const DATA = enum(u8) {
1365 NONE = 0,
1366 @"2LSB" = 1,
1367 @"2MSB" = 2,
1368 _,
1369
1370 pub const NUM = @typeInfo(DATA).@"enum".fields.len;
1088};1371};
10891372
1090pub const OSABI = enum(u8) {1373pub const OSABI = enum(u8) {
...@@ -1718,6 +2001,108 @@ pub const SHF_MIPS_STRING = 0x80000000;...@@ -1718,6 +2001,108 @@ pub const SHF_MIPS_STRING = 0x80000000;
1718/// Make code section unreadable when in execute-only mode2001/// Make code section unreadable when in execute-only mode
1719pub const SHF_ARM_PURECODE = 0x2000000;2002pub const SHF_ARM_PURECODE = 0x2000000;
17202003
2004pub const SHF = packed struct(Word) {
2005 /// Section data should be writable during execution.
2006 WRITE: bool = false,
2007 /// Section occupies memory during program execution.
2008 ALLOC: bool = false,
2009 /// Section contains executable machine instructions.
2010 EXECINSTR: bool = false,
2011 unused3: u1 = 0,
2012 /// The data in this section may be merged.
2013 MERGE: bool = false,
2014 /// The data in this section is null-terminated strings.
2015 STRINGS: bool = false,
2016 /// A field in this section holds a section header table index.
2017 INFO_LINK: bool = false,
2018 /// Adds special ordering requirements for link editors.
2019 LINK_ORDER: bool = false,
2020 /// This section requires special OS-specific processing to avoid incorrect behavior.
2021 OS_NONCONFORMING: bool = false,
2022 /// This section is a member of a section group.
2023 GROUP: bool = false,
2024 /// This section holds Thread-Local Storage.
2025 TLS: bool = false,
2026 /// Identifies a section containing compressed data.
2027 COMPRESSED: bool = false,
2028 unused12: u8 = 0,
2029 OS: packed union {
2030 MASK: u8,
2031 GNU: packed struct(u8) {
2032 unused0: u1 = 0,
2033 /// Not to be GCed by the linker
2034 RETAIN: bool = false,
2035 unused2: u6 = 0,
2036 },
2037 MIPS: packed struct(u8) {
2038 unused0: u4 = 0,
2039 /// Section contains text/data which may be replicated in other sections.
2040 /// Linker must retain only one copy.
2041 NODUPES: bool = false,
2042 /// Linker must generate implicit hidden weak names.
2043 NAMES: bool = false,
2044 /// Section data local to process.
2045 LOCAL: bool = false,
2046 /// Do not strip this section.
2047 NOSTRIP: bool = false,
2048 },
2049 ARM: packed struct(u8) {
2050 unused0: u5 = 0,
2051 /// Make code section unreadable when in execute-only mode
2052 PURECODE: bool = false,
2053 unused6: u2 = 0,
2054 },
2055 } = .{ .MASK = 0 },
2056 PROC: packed union {
2057 MASK: u4,
2058 XCORE: packed struct(u4) {
2059 /// All sections with the "d" flag are grouped together by the linker to form
2060 /// the data section and the dp register is set to the start of the section by
2061 /// the boot code.
2062 DP_SECTION: bool = false,
2063 /// All sections with the "c" flag are grouped together by the linker to form
2064 /// the constant pool and the cp register is set to the start of the constant
2065 /// pool by the boot code.
2066 CP_SECTION: bool = false,
2067 unused2: u1 = 0,
2068 /// This section is excluded from the final executable or shared library.
2069 EXCLUDE: bool = false,
2070 },
2071 X86_64: packed struct(u4) {
2072 /// If an object file section does not have this flag set, then it may not hold
2073 /// more than 2GB and can be freely referred to in objects using smaller code
2074 /// models. Otherwise, only objects using larger code models can refer to them.
2075 /// For example, a medium code model object can refer to data in a section that
2076 /// sets this flag besides being able to refer to data in a section that does
2077 /// not set it; likewise, a small code model object can refer only to code in a
2078 /// section that does not set this flag.
2079 LARGE: bool = false,
2080 unused1: u2 = 0,
2081 /// This section is excluded from the final executable or shared library.
2082 EXCLUDE: bool = false,
2083 },
2084 HEX: packed struct(u4) {
2085 /// All sections with the GPREL flag are grouped into a global data area
2086 /// for faster accesses
2087 GPREL: bool = false,
2088 unused1: u2 = 0,
2089 /// This section is excluded from the final executable or shared library.
2090 EXCLUDE: bool = false,
2091 },
2092 MIPS: packed struct(u4) {
2093 /// All sections with the GPREL flag are grouped into a global data area
2094 /// for faster accesses
2095 GPREL: bool = false,
2096 /// This section should be merged.
2097 MERGE: bool = false,
2098 /// Address size to be inferred from section entry size.
2099 ADDR: bool = false,
2100 /// Section data is string data by default.
2101 STRING: bool = false,
2102 },
2103 } = .{ .MASK = 0 },
2104};
2105
1721/// Execute2106/// Execute
1722pub const PF_X = 1;2107pub const PF_X = 1;
17232108
...@@ -1733,6 +2118,19 @@ pub const PF_MASKOS = 0x0ff00000;...@@ -1733,6 +2118,19 @@ pub const PF_MASKOS = 0x0ff00000;
1733/// Bits for processor-specific semantics.2118/// Bits for processor-specific semantics.
1734pub const PF_MASKPROC = 0xf0000000;2119pub const PF_MASKPROC = 0xf0000000;
17352120
2121pub const PF = packed struct(Word) {
2122 X: bool = false,
2123 W: bool = false,
2124 R: bool = false,
2125 unused3: u17 = 0,
2126 OS: packed union {
2127 MASK: u8,
2128 } = .{ .MASK = 0 },
2129 PROC: packed union {
2130 MASK: u4,
2131 } = .{ .MASK = 0 },
2132};
2133
1736/// Undefined section2134/// Undefined section
1737pub const SHN_UNDEF = 0;2135pub const SHN_UNDEF = 0;
1738/// Start of reserved indices2136/// Start of reserved indices
...@@ -2303,13 +2701,6 @@ pub const R_PPC64 = enum(u32) {...@@ -2303,13 +2701,6 @@ pub const R_PPC64 = enum(u32) {
2303 _,2701 _,
2304};2702};
23052703
2306pub const STV = enum(u3) {
2307 DEFAULT = 0,
2308 INTERNAL = 1,
2309 HIDDEN = 2,
2310 PROTECTED = 3,
2311};
2312
2313pub const ar_hdr = extern struct {2704pub const ar_hdr = extern struct {
2314 /// Member file name, sometimes / terminated.2705 /// Member file name, sometimes / terminated.
2315 ar_name: [16]u8,2706 ar_name: [16]u8,
lib/std/zig/system.zig+6-6
...@@ -516,15 +516,15 @@ pub fn abiAndDynamicLinkerFromFile(...@@ -516,15 +516,15 @@ pub fn abiAndDynamicLinkerFromFile(
516 const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf);516 const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf);
517 const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf);517 const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf);
518 if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;518 if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;
519 const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) {519 const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI.DATA]) {
520 elf.ELFDATA2LSB => .little,520 elf.ELFDATA2LSB => .little,
521 elf.ELFDATA2MSB => .big,521 elf.ELFDATA2MSB => .big,
522 else => return error.InvalidElfEndian,522 else => return error.InvalidElfEndian,
523 };523 };
524 const need_bswap = elf_endian != native_endian;524 const need_bswap = elf_endian != native_endian;
525 if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion;525 if (hdr32.e_ident[elf.EI.VERSION] != 1) return error.InvalidElfVersion;
526526
527 const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) {527 const is_64 = switch (hdr32.e_ident[elf.EI.CLASS]) {
528 elf.ELFCLASS32 => false,528 elf.ELFCLASS32 => false,
529 elf.ELFCLASS64 => true,529 elf.ELFCLASS64 => true,
530 else => return error.InvalidElfClass,530 else => return error.InvalidElfClass,
...@@ -920,15 +920,15 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {...@@ -920,15 +920,15 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion {
920 const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf);920 const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf);
921 const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf);921 const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf);
922 if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;922 if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic;
923 const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) {923 const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI.DATA]) {
924 elf.ELFDATA2LSB => .little,924 elf.ELFDATA2LSB => .little,
925 elf.ELFDATA2MSB => .big,925 elf.ELFDATA2MSB => .big,
926 else => return error.InvalidElfEndian,926 else => return error.InvalidElfEndian,
927 };927 };
928 const need_bswap = elf_endian != native_endian;928 const need_bswap = elf_endian != native_endian;
929 if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion;929 if (hdr32.e_ident[elf.EI.VERSION] != 1) return error.InvalidElfVersion;
930930
931 const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) {931 const is_64 = switch (hdr32.e_ident[elf.EI.CLASS]) {
932 elf.ELFCLASS32 => false,932 elf.ELFCLASS32 => false,
933 elf.ELFCLASS64 => true,933 elf.ELFCLASS64 => true,
934 else => return error.InvalidElfClass,934 else => return error.InvalidElfClass,
src/Compilation.zig+34-13
...@@ -177,7 +177,6 @@ debug_compiler_runtime_libs: bool,...@@ -177,7 +177,6 @@ debug_compiler_runtime_libs: bool,
177debug_compile_errors: bool,177debug_compile_errors: bool,
178/// Do not check this field directly. Instead, use the `debugIncremental` wrapper function.178/// Do not check this field directly. Instead, use the `debugIncremental` wrapper function.
179debug_incremental: bool,179debug_incremental: bool,
180incremental: bool,
181alloc_failure_occurred: bool = false,180alloc_failure_occurred: bool = false,
182last_update_was_cache_hit: bool = false,181last_update_was_cache_hit: bool = false,
183182
...@@ -256,7 +255,9 @@ mutex: if (builtin.single_threaded) struct {...@@ -256,7 +255,9 @@ mutex: if (builtin.single_threaded) struct {
256test_filters: []const []const u8,255test_filters: []const []const u8,
257256
258link_task_wait_group: WaitGroup = .{},257link_task_wait_group: WaitGroup = .{},
259link_prog_node: std.Progress.Node = std.Progress.Node.none,258link_prog_node: std.Progress.Node = .none,
259link_uav_prog_node: std.Progress.Node = .none,
260link_lazy_prog_node: std.Progress.Node = .none,
260261
261llvm_opt_bisect_limit: c_int,262llvm_opt_bisect_limit: c_int,
262263
...@@ -1746,7 +1747,6 @@ pub const CreateOptions = struct {...@@ -1746,7 +1747,6 @@ pub const CreateOptions = struct {
1746 debug_compiler_runtime_libs: bool = false,1747 debug_compiler_runtime_libs: bool = false,
1747 debug_compile_errors: bool = false,1748 debug_compile_errors: bool = false,
1748 debug_incremental: bool = false,1749 debug_incremental: bool = false,
1749 incremental: bool = false,
1750 /// Normally when you create a `Compilation`, Zig will automatically build1750 /// Normally when you create a `Compilation`, Zig will automatically build
1751 /// and link in required dependencies, such as compiler-rt and libc. When1751 /// and link in required dependencies, such as compiler-rt and libc. When
1752 /// building such dependencies themselves, this flag must be set to avoid1752 /// building such dependencies themselves, this flag must be set to avoid
...@@ -1982,6 +1982,7 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options...@@ -1982,6 +1982,7 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
1982 };1982 };
1983 if (have_zcu and (!need_llvm or use_llvm)) {1983 if (have_zcu and (!need_llvm or use_llvm)) {
1984 if (output_mode == .Obj) break :s .zcu;1984 if (output_mode == .Obj) break :s .zcu;
1985 if (options.config.use_new_linker) break :s .zcu;
1985 switch (target_util.zigBackend(target, use_llvm)) {1986 switch (target_util.zigBackend(target, use_llvm)) {
1986 else => {},1987 else => {},
1987 .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) {1988 .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) {
...@@ -2188,8 +2189,8 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options...@@ -2188,8 +2189,8 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
2188 .inherited = .{},2189 .inherited = .{},
2189 .global = options.config,2190 .global = options.config,
2190 .parent = options.root_mod,2191 .parent = options.root_mod,
2191 }) catch |err| return switch (err) {2192 }) catch |err| switch (err) {
2192 error.OutOfMemory => |e| return e,2193 error.OutOfMemory => return error.OutOfMemory,
2193 // None of these are possible because the configuration matches the root module2194 // None of these are possible because the configuration matches the root module
2194 // which already passed these checks.2195 // which already passed these checks.
2195 error.ValgrindUnsupportedOnTarget => unreachable,2196 error.ValgrindUnsupportedOnTarget => unreachable,
...@@ -2266,7 +2267,6 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options...@@ -2266,7 +2267,6 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
2266 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,2267 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
2267 .debug_compile_errors = options.debug_compile_errors,2268 .debug_compile_errors = options.debug_compile_errors,
2268 .debug_incremental = options.debug_incremental,2269 .debug_incremental = options.debug_incremental,
2269 .incremental = options.incremental,
2270 .root_name = root_name,2270 .root_name = root_name,
2271 .sysroot = sysroot,2271 .sysroot = sysroot,
2272 .windows_libs = .empty,2272 .windows_libs = .empty,
...@@ -2409,6 +2409,8 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options...@@ -2409,6 +2409,8 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
2409 // Synchronize with other matching comments: ZigOnlyHashStuff2409 // Synchronize with other matching comments: ZigOnlyHashStuff
2410 hash.add(use_llvm);2410 hash.add(use_llvm);
2411 hash.add(options.config.use_lib_llvm);2411 hash.add(options.config.use_lib_llvm);
2412 hash.add(options.config.use_lld);
2413 hash.add(options.config.use_new_linker);
2412 hash.add(options.config.dll_export_fns);2414 hash.add(options.config.dll_export_fns);
2413 hash.add(options.config.is_test);2415 hash.add(options.config.is_test);
2414 hash.addListOfBytes(options.test_filters);2416 hash.addListOfBytes(options.test_filters);
...@@ -3075,14 +3077,29 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -3075,14 +3077,29 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
30753077
3076 // The linker progress node is set up here instead of in `performAllTheWork`, because3078 // The linker progress node is set up here instead of in `performAllTheWork`, because
3077 // we also want it around during `flush`.3079 // we also want it around during `flush`.
3078 const have_link_node = comp.bin_file != null;3080 if (comp.bin_file) |lf| {
3079 if (have_link_node) {
3080 comp.link_prog_node = main_progress_node.start("Linking", 0);3081 comp.link_prog_node = main_progress_node.start("Linking", 0);
3082 if (lf.cast(.elf2)) |elf| {
3083 comp.link_prog_node.increaseEstimatedTotalItems(3);
3084 comp.link_uav_prog_node = comp.link_prog_node.start("Constants", 0);
3085 comp.link_lazy_prog_node = comp.link_prog_node.start("Synthetics", 0);
3086 elf.mf.update_prog_node = comp.link_prog_node.start("Relocations", elf.mf.updates.items.len);
3087 }
3081 }3088 }
3082 defer if (have_link_node) {3089 defer {
3083 comp.link_prog_node.end();3090 comp.link_prog_node.end();
3084 comp.link_prog_node = .none;3091 comp.link_prog_node = .none;
3085 };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;
3096 if (comp.bin_file) |lf| {
3097 if (lf.cast(.elf2)) |elf| {
3098 elf.mf.update_prog_node.end();
3099 elf.mf.update_prog_node = .none;
3100 }
3101 }
3102 }
30863103
3087 try comp.performAllTheWork(main_progress_node);3104 try comp.performAllTheWork(main_progress_node);
30883105
...@@ -3100,6 +3117,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -3100,6 +3117,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
3100 try pt.populateTestFunctions();3117 try pt.populateTestFunctions();
3101 }3118 }
31023119
3120 link.updateErrorData(pt);
3121
3103 try pt.processExports();3122 try pt.processExports();
3104 }3123 }
31053124
...@@ -3474,6 +3493,8 @@ fn addNonIncrementalStuffToCacheManifest(...@@ -3474,6 +3493,8 @@ fn addNonIncrementalStuffToCacheManifest(
34743493
3475 man.hash.add(comp.config.use_llvm);3494 man.hash.add(comp.config.use_llvm);
3476 man.hash.add(comp.config.use_lib_llvm);3495 man.hash.add(comp.config.use_lib_llvm);
3496 man.hash.add(comp.config.use_lld);
3497 man.hash.add(comp.config.use_new_linker);
3477 man.hash.add(comp.config.is_test);3498 man.hash.add(comp.config.is_test);
3478 man.hash.add(comp.config.import_memory);3499 man.hash.add(comp.config.import_memory);
3479 man.hash.add(comp.config.export_memory);3500 man.hash.add(comp.config.export_memory);
...@@ -4073,7 +4094,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {...@@ -4073,7 +4094,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
4073 defer sorted_failed_analysis.deinit(gpa);4094 defer sorted_failed_analysis.deinit(gpa);
4074 var added_any_analysis_error = false;4095 var added_any_analysis_error = false;
4075 for (sorted_failed_analysis.items(.key), sorted_failed_analysis.items(.value)) |anal_unit, error_msg| {4096 for (sorted_failed_analysis.items(.key), sorted_failed_analysis.items(.value)) |anal_unit, error_msg| {
4076 if (comp.incremental) {4097 if (comp.config.incremental) {
4077 const refs = try zcu.resolveReferences();4098 const refs = try zcu.resolveReferences();
4078 if (!refs.contains(anal_unit)) continue;4099 if (!refs.contains(anal_unit)) continue;
4079 }4100 }
...@@ -4240,7 +4261,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {...@@ -4240,7 +4261,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
42404261
4241 // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a4262 // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a
4242 // very common way for incremental compilation bugs to manifest, so let's always check it.4263 // very common way for incremental compilation bugs to manifest, so let's always check it.
4243 if (comp.zcu) |zcu| if (comp.incremental and bundle.root_list.items.len == 0) {4264 if (comp.zcu) |zcu| if (comp.config.incremental and bundle.root_list.items.len == 0) {
4244 for (zcu.transitive_failed_analysis.keys()) |failed_unit| {4265 for (zcu.transitive_failed_analysis.keys()) |failed_unit| {
4245 const refs = try zcu.resolveReferences();4266 const refs = try zcu.resolveReferences();
4246 var ref = refs.get(failed_unit) orelse continue;4267 var ref = refs.get(failed_unit) orelse continue;
...@@ -4949,7 +4970,7 @@ fn performAllTheWork(...@@ -4949,7 +4970,7 @@ fn performAllTheWork(
4949 tr.stats.n_reachable_files = @intCast(zcu.alive_files.count());4970 tr.stats.n_reachable_files = @intCast(zcu.alive_files.count());
4950 }4971 }
49514972
4952 if (comp.incremental) {4973 if (comp.config.incremental) {
4953 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);4974 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
4954 defer update_zir_refs_node.end();4975 defer update_zir_refs_node.end();
4955 try pt.updateZirRefs();4976 try pt.updateZirRefs();
src/Compilation/Config.zig+24
...@@ -49,6 +49,8 @@ use_lib_llvm: bool,...@@ -49,6 +49,8 @@ use_lib_llvm: bool,
49use_lld: bool,49use_lld: bool,
50c_frontend: CFrontend,50c_frontend: CFrontend,
51lto: std.zig.LtoMode,51lto: std.zig.LtoMode,
52use_new_linker: bool,
53incremental: bool,
52/// WASI-only. Type of WASI execution model ("command" or "reactor").54/// WASI-only. Type of WASI execution model ("command" or "reactor").
53/// Always set to `command` for non-WASI targets.55/// Always set to `command` for non-WASI targets.
54wasi_exec_model: std.builtin.WasiExecModel,56wasi_exec_model: std.builtin.WasiExecModel,
...@@ -104,6 +106,8 @@ pub const Options = struct {...@@ -104,6 +106,8 @@ pub const Options = struct {
104 use_lld: ?bool = null,106 use_lld: ?bool = null,
105 use_clang: ?bool = null,107 use_clang: ?bool = null,
106 lto: ?std.zig.LtoMode = null,108 lto: ?std.zig.LtoMode = null,
109 use_new_linker: ?bool = null,
110 incremental: bool = false,
107 /// WASI-only. Type of WASI execution model ("command" or "reactor").111 /// WASI-only. Type of WASI execution model ("command" or "reactor").
108 wasi_exec_model: ?std.builtin.WasiExecModel = null,112 wasi_exec_model: ?std.builtin.WasiExecModel = null,
109 import_memory: ?bool = null,113 import_memory: ?bool = null,
...@@ -147,6 +151,8 @@ pub const ResolveError = error{...@@ -147,6 +151,8 @@ pub const ResolveError = error{
147 LldUnavailable,151 LldUnavailable,
148 ClangUnavailable,152 ClangUnavailable,
149 DllExportFnsRequiresWindows,153 DllExportFnsRequiresWindows,
154 NewLinkerIncompatibleWithLld,
155 NewLinkerIncompatibleObjectFormat,
150};156};
151157
152pub fn resolve(options: Options) ResolveError!Config {158pub fn resolve(options: Options) ResolveError!Config {
...@@ -458,6 +464,22 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -458,6 +464,22 @@ pub fn resolve(options: Options) ResolveError!Config {
458 break :b .none;464 break :b .none;
459 };465 };
460466
467 const use_new_linker = b: {
468 if (use_lld) {
469 if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld;
470 break :b false;
471 }
472
473 if (!target_util.hasNewLinkerSupport(target.ofmt)) {
474 if (options.use_new_linker == true) return error.NewLinkerIncompatibleObjectFormat;
475 break :b false;
476 }
477
478 if (options.use_new_linker) |x| break :b x;
479
480 break :b options.incremental;
481 };
482
461 const root_strip = b: {483 const root_strip = b: {
462 if (options.root_strip) |x| break :b x;484 if (options.root_strip) |x| break :b x;
463 if (root_optimize_mode == .ReleaseSmall) break :b true;485 if (root_optimize_mode == .ReleaseSmall) break :b true;
...@@ -531,6 +553,8 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -531,6 +553,8 @@ pub fn resolve(options: Options) ResolveError!Config {
531 .root_error_tracing = root_error_tracing,553 .root_error_tracing = root_error_tracing,
532 .pie = pie,554 .pie = pie,
533 .lto = lto,555 .lto = lto,
556 .use_new_linker = use_new_linker,
557 .incremental = options.incremental,
534 .import_memory = import_memory,558 .import_memory = import_memory,
535 .export_memory = export_memory,559 .export_memory = export_memory,
536 .shared_memory = shared_memory,560 .shared_memory = shared_memory,
src/InternPool.zig+15-4
...@@ -6424,14 +6424,25 @@ pub const Alignment = enum(u6) {...@@ -6424,14 +6424,25 @@ pub const Alignment = enum(u6) {
6424 return n + 1;6424 return n + 1;
6425 }6425 }
64266426
6427 pub fn toStdMem(a: Alignment) std.mem.Alignment {
6428 assert(a != .none);
6429 return @enumFromInt(@intFromEnum(a));
6430 }
6431
6432 pub fn fromStdMem(a: std.mem.Alignment) Alignment {
6433 const r: Alignment = @enumFromInt(@intFromEnum(a));
6434 assert(r != .none);
6435 return r;
6436 }
6437
6427 const LlvmBuilderAlignment = std.zig.llvm.Builder.Alignment;6438 const LlvmBuilderAlignment = std.zig.llvm.Builder.Alignment;
64286439
6429 pub fn toLlvm(this: @This()) LlvmBuilderAlignment {6440 pub fn toLlvm(a: Alignment) LlvmBuilderAlignment {
6430 return @enumFromInt(@intFromEnum(this));6441 return @enumFromInt(@intFromEnum(a));
6431 }6442 }
64326443
6433 pub fn fromLlvm(other: LlvmBuilderAlignment) @This() {6444 pub fn fromLlvm(a: LlvmBuilderAlignment) Alignment {
6434 return @enumFromInt(@intFromEnum(other));6445 return @enumFromInt(@intFromEnum(a));
6435 }6446 }
6436};6447};
64376448
src/Sema.zig+8-8
...@@ -3032,7 +3032,7 @@ fn zirStructDecl(...@@ -3032,7 +3032,7 @@ fn zirStructDecl(
3032 });3032 });
3033 errdefer pt.destroyNamespace(new_namespace_index);3033 errdefer pt.destroyNamespace(new_namespace_index);
30343034
3035 if (pt.zcu.comp.incremental) {3035 if (pt.zcu.comp.config.incremental) {
3036 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });3036 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });
3037 }3037 }
30383038
...@@ -3430,7 +3430,7 @@ fn zirUnionDecl(...@@ -3430,7 +3430,7 @@ fn zirUnionDecl(
3430 });3430 });
3431 errdefer pt.destroyNamespace(new_namespace_index);3431 errdefer pt.destroyNamespace(new_namespace_index);
34323432
3433 if (pt.zcu.comp.incremental) {3433 if (pt.zcu.comp.config.incremental) {
3434 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });3434 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });
3435 }3435 }
34363436
...@@ -6217,7 +6217,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -6217,7 +6217,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
6217 if (ptr_info.byte_offset != 0) {6217 if (ptr_info.byte_offset != 0) {
6218 return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});6218 return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});
6219 }6219 }
6220 if (options.linkage == .internal) return;6220 if (zcu.llvm_object != null and options.linkage == .internal) return;
6221 const export_ty = Value.fromInterned(uav.val).typeOf(zcu);6221 const export_ty = Value.fromInterned(uav.val).typeOf(zcu);
6222 if (!try sema.validateExternType(export_ty, .other)) {6222 if (!try sema.validateExternType(export_ty, .other)) {
6223 return sema.failWithOwnedErrorMsg(block, msg: {6223 return sema.failWithOwnedErrorMsg(block, msg: {
...@@ -6256,7 +6256,7 @@ pub fn analyzeExport(...@@ -6256,7 +6256,7 @@ pub fn analyzeExport(
6256 const zcu = pt.zcu;6256 const zcu = pt.zcu;
6257 const ip = &zcu.intern_pool;6257 const ip = &zcu.intern_pool;
62586258
6259 if (options.linkage == .internal)6259 if (zcu.llvm_object != null and options.linkage == .internal)
6260 return;6260 return;
62616261
6262 try sema.ensureNavResolved(block, src, orig_nav_index, .fully);6262 try sema.ensureNavResolved(block, src, orig_nav_index, .fully);
...@@ -7709,7 +7709,7 @@ fn analyzeCall(...@@ -7709,7 +7709,7 @@ fn analyzeCall(
7709 // TODO: comptime call memoization is currently not supported under incremental compilation7709 // TODO: comptime call memoization is currently not supported under incremental compilation
7710 // since dependencies are not marked on callers. If we want to keep this around (we should7710 // since dependencies are not marked on callers. If we want to keep this around (we should
7711 // check that it's worthwhile first!), each memoized call needs an `AnalUnit`.7711 // check that it's worthwhile first!), each memoized call needs an `AnalUnit`.
7712 if (zcu.comp.incremental) break :m false;7712 if (zcu.comp.config.incremental) break :m false;
7713 if (!block.isComptime()) break :m false;7713 if (!block.isComptime()) break :m false;
7714 for (args) |a| {7714 for (args) |a| {
7715 const val = (try sema.resolveValue(a)).?;7715 const val = (try sema.resolveValue(a)).?;
...@@ -31208,7 +31208,7 @@ fn addReferenceEntry(...@@ -31208,7 +31208,7 @@ fn addReferenceEntry(
31208 .func => |f| assert(ip.unwrapCoercedFunc(f) == f), // for `.{ .func = f }`, `f` must be uncoerced31208 .func => |f| assert(ip.unwrapCoercedFunc(f) == f), // for `.{ .func = f }`, `f` must be uncoerced
31209 else => {},31209 else => {},
31210 }31210 }
31211 if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return;31211 if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return;
31212 const gop = try sema.references.getOrPut(sema.gpa, referenced_unit);31212 const gop = try sema.references.getOrPut(sema.gpa, referenced_unit);
31213 if (gop.found_existing) return;31213 if (gop.found_existing) return;
31214 try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: {31214 try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: {
...@@ -31225,7 +31225,7 @@ pub fn addTypeReferenceEntry(...@@ -31225,7 +31225,7 @@ pub fn addTypeReferenceEntry(
31225 referenced_type: InternPool.Index,31225 referenced_type: InternPool.Index,
31226) !void {31226) !void {
31227 const zcu = sema.pt.zcu;31227 const zcu = sema.pt.zcu;
31228 if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return;31228 if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return;
31229 const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type);31229 const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type);
31230 if (gop.found_existing) return;31230 if (gop.found_existing) return;
31231 try zcu.addTypeReference(sema.owner, referenced_type, src);31231 try zcu.addTypeReference(sema.owner, referenced_type, src);
...@@ -36875,7 +36875,7 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool...@@ -36875,7 +36875,7 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool
3687536875
36876pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {36876pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
36877 const pt = sema.pt;36877 const pt = sema.pt;
36878 if (!pt.zcu.comp.incremental) return;36878 if (!pt.zcu.comp.config.incremental) return;
3687936879
36880 const gop = try sema.dependencies.getOrPut(sema.gpa, dependee);36880 const gop = try sema.dependencies.getOrPut(sema.gpa, dependee);
36881 if (gop.found_existing) return;36881 if (gop.found_existing) return;
src/Value.zig+1-1
...@@ -23,7 +23,7 @@ pub fn format(val: Value, writer: *std.Io.Writer) !void {...@@ -23,7 +23,7 @@ pub fn format(val: Value, writer: *std.Io.Writer) !void {
2323
24/// This is a debug function. In order to print values in a meaningful way24/// This is a debug function. In order to print values in a meaningful way
25/// we also need access to the type.25/// we also need access to the type.
26pub fn dump(start_val: Value, w: std.Io.Writer) std.Io.Writer.Error!void {26pub fn dump(start_val: Value, w: *std.Io.Writer) std.Io.Writer.Error!void {
27 try w.print("(interned: {})", .{start_val.toIntern()});27 try w.print("(interned: {})", .{start_val.toIntern()});
28}28}
2929
src/Zcu.zig+1-1
...@@ -3166,7 +3166,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni...@@ -3166,7 +3166,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
3166}3166}
31673167
3168pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {3168pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
3169 if (!zcu.comp.incremental) return null;3169 if (!zcu.comp.config.incremental) return null;
31703170
3171 if (zcu.outdated.count() == 0) {3171 if (zcu.outdated.count() == 0) {
3172 // Any units in `potentially_outdated` must just be stuck in loops with one another: none of those3172 // Any units in `potentially_outdated` must just be stuck in loops with one another: none of those
src/Zcu/PerThread.zig+1-1
...@@ -1815,7 +1815,7 @@ fn createFileRootStruct(...@@ -1815,7 +1815,7 @@ fn createFileRootStruct(
1815 wip_ty.setName(ip, try file.internFullyQualifiedName(pt), .none);1815 wip_ty.setName(ip, try file.internFullyQualifiedName(pt), .none);
1816 ip.namespacePtr(namespace_index).owner_type = wip_ty.index;1816 ip.namespacePtr(namespace_index).owner_type = wip_ty.index;
18171817
1818 if (zcu.comp.incremental) {1818 if (zcu.comp.config.incremental) {
1819 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });1819 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });
1820 }1820 }
18211821
src/arch/riscv64/CodeGen.zig+5-3
...@@ -858,9 +858,11 @@ pub fn generateLazy(...@@ -858,9 +858,11 @@ pub fn generateLazy(
858 pt: Zcu.PerThread,858 pt: Zcu.PerThread,
859 src_loc: Zcu.LazySrcLoc,859 src_loc: Zcu.LazySrcLoc,
860 lazy_sym: link.File.LazySymbol,860 lazy_sym: link.File.LazySymbol,
861 code: *std.ArrayListUnmanaged(u8),861 atom_index: u32,
862 w: *std.Io.Writer,
862 debug_output: link.File.DebugInfoOutput,863 debug_output: link.File.DebugInfoOutput,
863) CodeGenError!void {864) (CodeGenError || std.Io.Writer.Error)!void {
865 _ = atom_index;
864 const comp = bin_file.comp;866 const comp = bin_file.comp;
865 const gpa = comp.gpa;867 const gpa = comp.gpa;
866 const mod = comp.root_mod;868 const mod = comp.root_mod;
...@@ -914,7 +916,7 @@ pub fn generateLazy(...@@ -914,7 +916,7 @@ pub fn generateLazy(
914 },916 },
915 .bin_file = bin_file,917 .bin_file = bin_file,
916 .debug_output = debug_output,918 .debug_output = debug_output,
917 .code = code,919 .w = w,
918 .prev_di_pc = undefined, // no debug info yet920 .prev_di_pc = undefined, // no debug info yet
919 .prev_di_line = undefined, // no debug info yet921 .prev_di_line = undefined, // no debug info yet
920 .prev_di_column = undefined, // no debug info yet922 .prev_di_column = undefined, // no debug info yet
src/arch/riscv64/Emit.zig+8-8
...@@ -3,7 +3,7 @@...@@ -3,7 +3,7 @@
3bin_file: *link.File,3bin_file: *link.File,
4lower: Lower,4lower: Lower,
5debug_output: link.File.DebugInfoOutput,5debug_output: link.File.DebugInfoOutput,
6code: *std.ArrayListUnmanaged(u8),6w: *std.Io.Writer,
77
8prev_di_line: u32,8prev_di_line: u32,
9prev_di_column: u32,9prev_di_column: u32,
...@@ -13,7 +13,7 @@ prev_di_pc: usize,...@@ -13,7 +13,7 @@ prev_di_pc: usize,
13code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,13code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
14relocs: std.ArrayListUnmanaged(Reloc) = .empty,14relocs: std.ArrayListUnmanaged(Reloc) = .empty,
1515
16pub const Error = Lower.Error || error{16pub const Error = Lower.Error || std.Io.Writer.Error || error{
17 EmitFail,17 EmitFail,
18};18};
1919
...@@ -25,13 +25,13 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -25,13 +25,13 @@ pub fn emitMir(emit: *Emit) Error!void {
25 try emit.code_offset_mapping.putNoClobber(25 try emit.code_offset_mapping.putNoClobber(
26 emit.lower.allocator,26 emit.lower.allocator,
27 mir_index,27 mir_index,
28 @intCast(emit.code.items.len),28 @intCast(emit.w.end),
29 );29 );
30 const lowered = try emit.lower.lowerMir(mir_index, .{ .allow_frame_locs = true });30 const lowered = try emit.lower.lowerMir(mir_index, .{ .allow_frame_locs = true });
31 var lowered_relocs = lowered.relocs;31 var lowered_relocs = lowered.relocs;
32 for (lowered.insts, 0..) |lowered_inst, lowered_index| {32 for (lowered.insts, 0..) |lowered_inst, lowered_index| {
33 const start_offset: u32 = @intCast(emit.code.items.len);33 const start_offset: u32 = @intCast(emit.w.end);
34 std.mem.writeInt(u32, try emit.code.addManyAsArray(gpa, 4), lowered_inst.toU32(), .little);34 try emit.w.writeInt(u32, lowered_inst.toU32(), .little);
3535
36 while (lowered_relocs.len > 0 and36 while (lowered_relocs.len > 0 and
37 lowered_relocs[0].lowered_inst_index == lowered_index) : ({37 lowered_relocs[0].lowered_inst_index == lowered_index) : ({
...@@ -175,7 +175,7 @@ fn fixupRelocs(emit: *Emit) Error!void {...@@ -175,7 +175,7 @@ fn fixupRelocs(emit: *Emit) Error!void {
175 return emit.fail("relocation target not found!", .{});175 return emit.fail("relocation target not found!", .{});
176176
177 const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source));177 const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source));
178 const code: *[4]u8 = emit.code.items[reloc.source + reloc.offset ..][0..4];178 const code = emit.w.buffered()[reloc.source + reloc.offset ..][0..4];
179179
180 switch (reloc.fmt) {180 switch (reloc.fmt) {
181 .J => riscv_util.writeInstJ(code, @bitCast(disp)),181 .J => riscv_util.writeInstJ(code, @bitCast(disp)),
...@@ -187,7 +187,7 @@ fn fixupRelocs(emit: *Emit) Error!void {...@@ -187,7 +187,7 @@ fn fixupRelocs(emit: *Emit) Error!void {
187187
188fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {188fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
189 const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line);189 const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line);
190 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;190 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
191 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });191 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });
192 switch (emit.debug_output) {192 switch (emit.debug_output) {
193 .dwarf => |dw| {193 .dwarf => |dw| {
...@@ -196,7 +196,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {...@@ -196,7 +196,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void {
196 try dw.advancePCAndLine(delta_line, delta_pc);196 try dw.advancePCAndLine(delta_line, delta_pc);
197 emit.prev_di_line = line;197 emit.prev_di_line = line;
198 emit.prev_di_column = column;198 emit.prev_di_column = column;
199 emit.prev_di_pc = emit.code.items.len;199 emit.prev_di_pc = emit.w.end;
200 },200 },
201 .none => {},201 .none => {},
202 }202 }
src/arch/riscv64/Mir.zig+5-3
...@@ -109,9 +109,11 @@ pub fn emit(...@@ -109,9 +109,11 @@ pub fn emit(
109 pt: Zcu.PerThread,109 pt: Zcu.PerThread,
110 src_loc: Zcu.LazySrcLoc,110 src_loc: Zcu.LazySrcLoc,
111 func_index: InternPool.Index,111 func_index: InternPool.Index,
112 code: *std.ArrayListUnmanaged(u8),112 atom_index: u32,
113 w: *std.Io.Writer,
113 debug_output: link.File.DebugInfoOutput,114 debug_output: link.File.DebugInfoOutput,
114) codegen.CodeGenError!void {115) (codegen.CodeGenError || std.Io.Writer.Error)!void {
116 _ = atom_index;
115 const zcu = pt.zcu;117 const zcu = pt.zcu;
116 const comp = zcu.comp;118 const comp = zcu.comp;
117 const gpa = comp.gpa;119 const gpa = comp.gpa;
...@@ -132,7 +134,7 @@ pub fn emit(...@@ -132,7 +134,7 @@ pub fn emit(
132 },134 },
133 .bin_file = lf,135 .bin_file = lf,
134 .debug_output = debug_output,136 .debug_output = debug_output,
135 .code = code,137 .w = w,
136 .prev_di_pc = 0,138 .prev_di_pc = 0,
137 .prev_di_line = func.lbrace_line,139 .prev_di_line = func.lbrace_line,
138 .prev_di_column = func.lbrace_column,140 .prev_di_column = func.lbrace_column,
src/arch/sparc64/Emit.zig+7-12
...@@ -21,7 +21,7 @@ debug_output: link.File.DebugInfoOutput,...@@ -21,7 +21,7 @@ debug_output: link.File.DebugInfoOutput,
21target: *const std.Target,21target: *const std.Target,
22err_msg: ?*ErrorMsg = null,22err_msg: ?*ErrorMsg = null,
23src_loc: Zcu.LazySrcLoc,23src_loc: Zcu.LazySrcLoc,
24code: *std.ArrayListUnmanaged(u8),24w: *std.Io.Writer,
2525
26prev_di_line: u32,26prev_di_line: u32,
27prev_di_column: u32,27prev_di_column: u32,
...@@ -40,7 +40,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUn...@@ -40,7 +40,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUn
40/// instruction40/// instruction
41code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,41code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty,
4242
43const InnerError = error{43const InnerError = std.Io.Writer.Error || error{
44 OutOfMemory,44 OutOfMemory,
45 EmitFail,45 EmitFail,
46};46};
...@@ -292,7 +292,7 @@ fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -292,7 +292,7 @@ fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
292 .bpcc => switch (tag) {292 .bpcc => switch (tag) {
293 .bpcc => {293 .bpcc => {
294 const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int;294 const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int;
295 const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_int.inst).?)) - @as(i64, @intCast(emit.code.items.len));295 const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_int.inst).?)) - @as(i64, @intCast(emit.w.end));
296 log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset });296 log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset });
297297
298 try emit.writeInstruction(298 try emit.writeInstruction(
...@@ -310,7 +310,7 @@ fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -310,7 +310,7 @@ fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void {
310 .bpr => switch (tag) {310 .bpr => switch (tag) {
311 .bpr => {311 .bpr => {
312 const branch_predict_reg = emit.mir.instructions.items(.data)[inst].branch_predict_reg;312 const branch_predict_reg = emit.mir.instructions.items(.data)[inst].branch_predict_reg;
313 const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_reg.inst).?)) - @as(i64, @intCast(emit.code.items.len));313 const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_reg.inst).?)) - @as(i64, @intCast(emit.w.end));
314 log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset });314 log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset });
315315
316 try emit.writeInstruction(316 try emit.writeInstruction(
...@@ -494,13 +494,13 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index {...@@ -494,13 +494,13 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index {
494494
495fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {495fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {
496 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));496 const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line));
497 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;497 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
498 switch (emit.debug_output) {498 switch (emit.debug_output) {
499 .dwarf => |dbg_out| {499 .dwarf => |dbg_out| {
500 try dbg_out.advancePCAndLine(delta_line, delta_pc);500 try dbg_out.advancePCAndLine(delta_line, delta_pc);
501 emit.prev_di_line = line;501 emit.prev_di_line = line;
502 emit.prev_di_column = column;502 emit.prev_di_column = column;
503 emit.prev_di_pc = emit.code.items.len;503 emit.prev_di_pc = emit.w.end;
504 },504 },
505 else => {},505 else => {},
506 }506 }
...@@ -675,13 +675,8 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType {...@@ -675,13 +675,8 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType {
675}675}
676676
677fn writeInstruction(emit: *Emit, instruction: Instruction) !void {677fn writeInstruction(emit: *Emit, instruction: Instruction) !void {
678 const comp = emit.bin_file.comp;
679 const gpa = comp.gpa;
680
681 // SPARCv9 instructions are always arranged in BE regardless of the678 // SPARCv9 instructions are always arranged in BE regardless of the
682 // endianness mode the CPU is running in (Section 3.1 of the ISA specification).679 // endianness mode the CPU is running in (Section 3.1 of the ISA specification).
683 // This is to ease porting in case someone wants to do a LE SPARCv9 backend.680 // This is to ease porting in case someone wants to do a LE SPARCv9 backend.
684 const endian: Endian = .big;681 try emit.w.writeInt(u32, instruction.toU32(), .big);
685
686 std.mem.writeInt(u32, try emit.code.addManyAsArray(gpa, 4), instruction.toU32(), endian);
687}682}
src/arch/sparc64/Mir.zig+5-3
...@@ -380,9 +380,11 @@ pub fn emit(...@@ -380,9 +380,11 @@ pub fn emit(
380 pt: Zcu.PerThread,380 pt: Zcu.PerThread,
381 src_loc: Zcu.LazySrcLoc,381 src_loc: Zcu.LazySrcLoc,
382 func_index: InternPool.Index,382 func_index: InternPool.Index,
383 code: *std.ArrayListUnmanaged(u8),383 atom_index: u32,
384 w: *std.Io.Writer,
384 debug_output: link.File.DebugInfoOutput,385 debug_output: link.File.DebugInfoOutput,
385) codegen.CodeGenError!void {386) (codegen.CodeGenError || std.Io.Writer.Error)!void {
387 _ = atom_index;
386 const zcu = pt.zcu;388 const zcu = pt.zcu;
387 const func = zcu.funcInfo(func_index);389 const func = zcu.funcInfo(func_index);
388 const nav = func.owner_nav;390 const nav = func.owner_nav;
...@@ -393,7 +395,7 @@ pub fn emit(...@@ -393,7 +395,7 @@ pub fn emit(
393 .debug_output = debug_output,395 .debug_output = debug_output,
394 .target = &mod.resolved_target.result,396 .target = &mod.resolved_target.result,
395 .src_loc = src_loc,397 .src_loc = src_loc,
396 .code = code,398 .w = w,
397 .prev_di_pc = 0,399 .prev_di_pc = 0,
398 .prev_di_line = func.lbrace_line,400 .prev_di_line = func.lbrace_line,
399 .prev_di_column = func.lbrace_column,401 .prev_di_column = func.lbrace_column,
src/arch/x86_64/CodeGen.zig+9-8
...@@ -550,9 +550,9 @@ pub const MCValue = union(enum) {...@@ -550,9 +550,9 @@ pub const MCValue = union(enum) {
550 @tagName(pl.reg),550 @tagName(pl.reg),
551 }),551 }),
552 .indirect => |pl| try w.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),552 .indirect => |pl| try w.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
553 .indirect_load_frame => |pl| try w.print("[[{} + 0x{x}]]", .{ pl.index, pl.off }),553 .indirect_load_frame => |pl| try w.print("[[{f} + 0x{x}]]", .{ pl.index, pl.off }),
554 .load_frame => |pl| try w.print("[{} + 0x{x}]", .{ pl.index, pl.off }),554 .load_frame => |pl| try w.print("[{f} + 0x{x}]", .{ pl.index, pl.off }),
555 .lea_frame => |pl| try w.print("{} + 0x{x}", .{ pl.index, pl.off }),555 .lea_frame => |pl| try w.print("{f} + 0x{x}", .{ pl.index, pl.off }),
556 .load_nav => |pl| try w.print("[nav:{d}]", .{@intFromEnum(pl)}),556 .load_nav => |pl| try w.print("[nav:{d}]", .{@intFromEnum(pl)}),
557 .lea_nav => |pl| try w.print("nav:{d}", .{@intFromEnum(pl)}),557 .lea_nav => |pl| try w.print("nav:{d}", .{@intFromEnum(pl)}),
558 .load_uav => |pl| try w.print("[uav:{d}]", .{@intFromEnum(pl.val)}),558 .load_uav => |pl| try w.print("[uav:{d}]", .{@intFromEnum(pl.val)}),
...@@ -561,10 +561,10 @@ pub const MCValue = union(enum) {...@@ -561,10 +561,10 @@ pub const MCValue = union(enum) {
561 .lea_lazy_sym => |pl| try w.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }),561 .lea_lazy_sym => |pl| try w.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }),
562 .load_extern_func => |pl| try w.print("[extern:{d}]", .{@intFromEnum(pl)}),562 .load_extern_func => |pl| try w.print("[extern:{d}]", .{@intFromEnum(pl)}),
563 .lea_extern_func => |pl| try w.print("extern:{d}", .{@intFromEnum(pl)}),563 .lea_extern_func => |pl| try w.print("extern:{d}", .{@intFromEnum(pl)}),
564 .elementwise_args => |pl| try w.print("elementwise:{d}:[{} + 0x{x}]", .{564 .elementwise_args => |pl| try w.print("elementwise:{d}:[{f} + 0x{x}]", .{
565 pl.regs, pl.frame_index, pl.frame_off,565 pl.regs, pl.frame_index, pl.frame_off,
566 }),566 }),
567 .reserved_frame => |pl| try w.print("(dead:{})", .{pl}),567 .reserved_frame => |pl| try w.print("(dead:{f})", .{pl}),
568 .air_ref => |pl| try w.print("(air:0x{x})", .{@intFromEnum(pl)}),568 .air_ref => |pl| try w.print("(air:0x{x})", .{@intFromEnum(pl)}),
569 }569 }
570 }570 }
...@@ -1038,7 +1038,8 @@ pub fn generateLazy(...@@ -1038,7 +1038,8 @@ pub fn generateLazy(
1038 pt: Zcu.PerThread,1038 pt: Zcu.PerThread,
1039 src_loc: Zcu.LazySrcLoc,1039 src_loc: Zcu.LazySrcLoc,
1040 lazy_sym: link.File.LazySymbol,1040 lazy_sym: link.File.LazySymbol,
1041 code: *std.ArrayListUnmanaged(u8),1041 atom_index: u32,
1042 w: *std.Io.Writer,
1042 debug_output: link.File.DebugInfoOutput,1043 debug_output: link.File.DebugInfoOutput,
1043) codegen.CodeGenError!void {1044) codegen.CodeGenError!void {
1044 const gpa = pt.zcu.gpa;1045 const gpa = pt.zcu.gpa;
...@@ -1081,7 +1082,7 @@ pub fn generateLazy(...@@ -1081,7 +1082,7 @@ pub fn generateLazy(
1081 else => |e| return e,1082 else => |e| return e,
1082 };1083 };
10831084
1084 try function.getTmpMir().emitLazy(bin_file, pt, src_loc, lazy_sym, code, debug_output);1085 try function.getTmpMir().emitLazy(bin_file, pt, src_loc, lazy_sym, atom_index, w, debug_output);
1085}1086}
10861087
1087const FormatNavData = struct {1088const FormatNavData = struct {
...@@ -2022,7 +2023,7 @@ fn gen(...@@ -2022,7 +2023,7 @@ fn gen(
2022 .{},2023 .{},
2023 );2024 );
2024 self.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } };2025 self.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } };
2025 tracking_log.debug("spill {f} to {}", .{ self.ret_mcv.long, frame_index });2026 tracking_log.debug("spill {f} to {f}", .{ self.ret_mcv.long, frame_index });
2026 },2027 },
2027 else => unreachable,2028 else => unreachable,
2028 }2029 }
src/arch/x86_64/Emit.zig+76-32
...@@ -6,7 +6,7 @@ pt: Zcu.PerThread,...@@ -6,7 +6,7 @@ pt: Zcu.PerThread,
6pic: bool,6pic: bool,
7atom_index: u32,7atom_index: u32,
8debug_output: link.File.DebugInfoOutput,8debug_output: link.File.DebugInfoOutput,
9code: *std.ArrayListUnmanaged(u8),9w: *std.Io.Writer,
1010
11prev_di_loc: Loc,11prev_di_loc: Loc,
12/// Relative to the beginning of `code`.12/// Relative to the beginning of `code`.
...@@ -18,7 +18,8 @@ table_relocs: std.ArrayListUnmanaged(TableReloc),...@@ -18,7 +18,8 @@ table_relocs: std.ArrayListUnmanaged(TableReloc),
1818
19pub const Error = Lower.Error || error{19pub const Error = Lower.Error || error{
20 EmitFail,20 EmitFail,
21} || link.File.UpdateDebugInfoError;21 NotFile,
22} || std.posix.MMapError || std.posix.MRemapError || link.File.UpdateDebugInfoError;
2223
23pub fn emitMir(emit: *Emit) Error!void {24pub fn emitMir(emit: *Emit) Error!void {
24 const comp = emit.bin_file.comp;25 const comp = emit.bin_file.comp;
...@@ -29,12 +30,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -29,12 +30,12 @@ pub fn emitMir(emit: *Emit) Error!void {
29 var local_index: usize = 0;30 var local_index: usize = 0;
30 for (0..emit.lower.mir.instructions.len) |mir_i| {31 for (0..emit.lower.mir.instructions.len) |mir_i| {
31 const mir_index: Mir.Inst.Index = @intCast(mir_i);32 const mir_index: Mir.Inst.Index = @intCast(mir_i);
32 emit.code_offset_mapping.items[mir_index] = @intCast(emit.code.items.len);33 emit.code_offset_mapping.items[mir_index] = @intCast(emit.w.end);
33 const lowered = try emit.lower.lowerMir(mir_index);34 const lowered = try emit.lower.lowerMir(mir_index);
34 var lowered_relocs = lowered.relocs;35 var lowered_relocs = lowered.relocs;
35 lowered_inst: for (lowered.insts, 0..) |lowered_inst, lowered_index| {36 lowered_inst: for (lowered.insts, 0..) |lowered_inst, lowered_index| {
36 if (lowered_inst.prefix == .directive) {37 if (lowered_inst.prefix == .directive) {
37 const start_offset: u32 = @intCast(emit.code.items.len);38 const start_offset: u32 = @intCast(emit.w.end);
38 switch (emit.debug_output) {39 switch (emit.debug_output) {
39 .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) {40 .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) {
40 .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{41 .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{
...@@ -164,6 +165,8 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -164,6 +165,8 @@ pub fn emitMir(emit: *Emit) Error!void {
164 .index = if (emit.bin_file.cast(.elf)) |elf_file|165 .index = if (emit.bin_file.cast(.elf)) |elf_file|
165 elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, emit.pt, lazy_sym) catch |err|166 elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, emit.pt, lazy_sym) catch |err|
166 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})167 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
168 else if (emit.bin_file.cast(.elf2)) |elf|
169 @intFromEnum(try elf.lazySymbol(lazy_sym))
167 else if (emit.bin_file.cast(.macho)) |macho_file|170 else if (emit.bin_file.cast(.macho)) |macho_file|
168 macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|171 macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|
169 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})172 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
...@@ -180,12 +183,15 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -180,12 +183,15 @@ pub fn emitMir(emit: *Emit) Error!void {
180 .extern_func => |extern_func| .{183 .extern_func => |extern_func| .{
181 .index = if (emit.bin_file.cast(.elf)) |elf_file|184 .index = if (emit.bin_file.cast(.elf)) |elf_file|
182 try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)185 try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
183 else if (emit.bin_file.cast(.macho)) |macho_file|186 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
187 .name = extern_func.toSlice(&emit.lower.mir).?,
188 .type = .FUNC,
189 })) else if (emit.bin_file.cast(.macho)) |macho_file|
184 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)190 try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
185 else if (emit.bin_file.cast(.coff)) |coff_file|191 else if (emit.bin_file.cast(.coff)) |coff_file|
186 try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt")192 try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt")
187 else193 else
188 return emit.fail("external symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),194 return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}),
189 .is_extern = true,195 .is_extern = true,
190 .type = .symbol,196 .type = .symbol,
191 },197 },
...@@ -205,7 +211,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -205,7 +211,7 @@ pub fn emitMir(emit: *Emit) Error!void {
205 },211 },
206 else => {},212 else => {},
207 }213 }
208 if (emit.bin_file.cast(.elf)) |_| {214 if (emit.bin_file.cast(.elf) != null or emit.bin_file.cast(.elf2) != null) {
209 if (!emit.pic) switch (lowered_inst.encoding.mnemonic) {215 if (!emit.pic) switch (lowered_inst.encoding.mnemonic) {
210 .lea => try emit.encodeInst(try .new(.none, .mov, &.{216 .lea => try emit.encodeInst(try .new(.none, .mov, &.{
211 lowered_inst.ops[0],217 lowered_inst.ops[0],
...@@ -315,7 +321,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -315,7 +321,7 @@ pub fn emitMir(emit: *Emit) Error!void {
315 },321 },
316 .branch, .tls => unreachable,322 .branch, .tls => unreachable,
317 .tlv => {323 .tlv => {
318 if (emit.bin_file.cast(.elf)) |elf_file| {324 if (emit.bin_file.cast(.elf) != null or emit.bin_file.cast(.elf2) != null) {
319 // TODO handle extern TLS vars, i.e., emit GD model325 // TODO handle extern TLS vars, i.e., emit GD model
320 if (emit.pic) switch (lowered_inst.encoding.mnemonic) {326 if (emit.pic) switch (lowered_inst.encoding.mnemonic) {
321 .lea, .mov => {327 .lea, .mov => {
...@@ -337,7 +343,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -337,7 +343,12 @@ pub fn emitMir(emit: *Emit) Error!void {
337 }, emit.lower.target), &.{.{343 }, emit.lower.target), &.{.{
338 .op_index = 0,344 .op_index = 0,
339 .target = .{345 .target = .{
340 .index = try elf_file.getGlobalSymbol("__tls_get_addr", null),346 .index = if (emit.bin_file.cast(.elf)) |elf_file|
347 try elf_file.getGlobalSymbol("__tls_get_addr", null)
348 else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
349 .name = "__tls_get_addr",
350 .type = .FUNC,
351 })) else unreachable,
341 .is_extern = true,352 .is_extern = true,
342 .type = .branch,353 .type = .branch,
343 },354 },
...@@ -441,7 +452,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -441,7 +452,7 @@ pub fn emitMir(emit: *Emit) Error!void {
441 log.debug("mirDbgEnterBlock (line={d}, col={d})", .{452 log.debug("mirDbgEnterBlock (line={d}, col={d})", .{
442 emit.prev_di_loc.line, emit.prev_di_loc.column,453 emit.prev_di_loc.line, emit.prev_di_loc.column,
443 });454 });
444 try dwarf.enterBlock(emit.code.items.len);455 try dwarf.enterBlock(emit.w.end);
445 },456 },
446 .none => {},457 .none => {},
447 },458 },
...@@ -450,7 +461,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -450,7 +461,7 @@ pub fn emitMir(emit: *Emit) Error!void {
450 log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{461 log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{
451 emit.prev_di_loc.line, emit.prev_di_loc.column,462 emit.prev_di_loc.line, emit.prev_di_loc.column,
452 });463 });
453 try dwarf.leaveBlock(emit.code.items.len);464 try dwarf.leaveBlock(emit.w.end);
454 },465 },
455 .none => {},466 .none => {},
456 },467 },
...@@ -459,7 +470,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -459,7 +470,7 @@ pub fn emitMir(emit: *Emit) Error!void {
459 log.debug("mirDbgEnterInline (line={d}, col={d})", .{470 log.debug("mirDbgEnterInline (line={d}, col={d})", .{
460 emit.prev_di_loc.line, emit.prev_di_loc.column,471 emit.prev_di_loc.line, emit.prev_di_loc.column,
461 });472 });
462 try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.code.items.len, emit.prev_di_loc.line, emit.prev_di_loc.column);473 try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column);
463 },474 },
464 .none => {},475 .none => {},
465 },476 },
...@@ -468,7 +479,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -468,7 +479,7 @@ pub fn emitMir(emit: *Emit) Error!void {
468 log.debug("mirDbgLeaveInline (line={d}, col={d})", .{479 log.debug("mirDbgLeaveInline (line={d}, col={d})", .{
469 emit.prev_di_loc.line, emit.prev_di_loc.column,480 emit.prev_di_loc.line, emit.prev_di_loc.column,
470 });481 });
471 try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.code.items.len);482 try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end);
472 },483 },
473 .none => {},484 .none => {},
474 },485 },
...@@ -634,7 +645,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -634,7 +645,7 @@ pub fn emitMir(emit: *Emit) Error!void {
634 for (emit.relocs.items) |reloc| {645 for (emit.relocs.items) |reloc| {
635 const target = emit.code_offset_mapping.items[reloc.target];646 const target = emit.code_offset_mapping.items[reloc.target];
636 const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.inst_offset + reloc.inst_length)) + reloc.target_offset;647 const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.inst_offset + reloc.inst_length)) + reloc.target_offset;
637 const inst_bytes = emit.code.items[reloc.inst_offset..][0..reloc.inst_length];648 const inst_bytes = emit.w.buffered()[reloc.inst_offset..][0..reloc.inst_length];
638 switch (reloc.source_length) {649 switch (reloc.source_length) {
639 else => unreachable,650 else => unreachable,
640 inline 1, 4 => |source_length| std.mem.writeInt(651 inline 1, 4 => |source_length| std.mem.writeInt(
...@@ -646,12 +657,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -646,12 +657,12 @@ pub fn emitMir(emit: *Emit) Error!void {
646 }657 }
647 }658 }
648 if (emit.lower.mir.table.len > 0) {659 if (emit.lower.mir.table.len > 0) {
660 const ptr_size = @divExact(emit.lower.target.ptrBitWidth(), 8);
661 var table_offset = std.mem.alignForward(u32, @intCast(emit.w.end), ptr_size);
649 if (emit.bin_file.cast(.elf)) |elf_file| {662 if (emit.bin_file.cast(.elf)) |elf_file| {
650 const zo = elf_file.zigObjectPtr().?;663 const zo = elf_file.zigObjectPtr().?;
651 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;664 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
652665
653 const ptr_size = @divExact(emit.lower.target.ptrBitWidth(), 8);
654 var table_offset = std.mem.alignForward(u32, @intCast(emit.code.items.len), ptr_size);
655 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{666 for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{
656 .r_offset = table_reloc.source_offset,667 .r_offset = table_reloc.source_offset,
657 .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32"),668 .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32"),
...@@ -665,7 +676,26 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -665,7 +676,26 @@ pub fn emitMir(emit: *Emit) Error!void {
665 }, zo);676 }, zo);
666 table_offset += ptr_size;677 table_offset += ptr_size;
667 }678 }
668 try emit.code.appendNTimes(gpa, 0, table_offset - emit.code.items.len);679 try emit.w.splatByteAll(0, table_offset - emit.w.end);
680 } else if (emit.bin_file.cast(.elf2)) |elf| {
681 for (emit.table_relocs.items) |table_reloc| try elf.addReloc(
682 @enumFromInt(emit.atom_index),
683 table_reloc.source_offset,
684 @enumFromInt(emit.atom_index),
685 @as(i64, table_offset) + table_reloc.target_offset,
686 .{ .x86_64 = .@"32" },
687 );
688 for (emit.lower.mir.table) |entry| {
689 try elf.addReloc(
690 @enumFromInt(emit.atom_index),
691 table_offset,
692 @enumFromInt(emit.atom_index),
693 emit.code_offset_mapping.items[entry],
694 .{ .x86_64 = .@"64" },
695 );
696 table_offset += ptr_size;
697 }
698 try emit.w.splatByteAll(0, table_offset - emit.w.end);
669 } else unreachable;699 } else unreachable;
670 }700 }
671}701}
...@@ -696,16 +726,12 @@ const RelocInfo = struct {...@@ -696,16 +726,12 @@ const RelocInfo = struct {
696fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocInfo) Error!void {726fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocInfo) Error!void {
697 const comp = emit.bin_file.comp;727 const comp = emit.bin_file.comp;
698 const gpa = comp.gpa;728 const gpa = comp.gpa;
699 const start_offset: u32 = @intCast(emit.code.items.len);729 const start_offset: u32 = @intCast(emit.w.end);
700 {730 lowered_inst.encode(emit.w, .{}) catch |err| switch (err) {
701 var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, emit.code);731 error.WriteFailed => return error.OutOfMemory,
702 defer emit.code.* = aw.toArrayList();732 else => |e| return e,
703 lowered_inst.encode(&aw.writer, .{}) catch |err| switch (err) {733 };
704 error.WriteFailed => return error.OutOfMemory,734 const end_offset: u32 = @intCast(emit.w.end);
705 else => |e| return e,
706 };
707 }
708 const end_offset: u32 = @intCast(emit.code.items.len);
709 for (reloc_info) |reloc| switch (reloc.target.type) {735 for (reloc_info) |reloc| switch (reloc.target.type) {
710 .inst => {736 .inst => {
711 const inst_length: u4 = @intCast(end_offset - start_offset);737 const inst_length: u4 = @intCast(end_offset - start_offset);
...@@ -769,7 +795,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -769,7 +795,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
769 .symbolnum = @intCast(reloc.target.index),795 .symbolnum = @intCast(reloc.target.index),
770 },796 },
771 });797 });
772 } else if (emit.bin_file.cast(.coff)) |coff_file| {798 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
799 @enumFromInt(emit.atom_index),
800 end_offset - 4,
801 @enumFromInt(reloc.target.index),
802 reloc.off,
803 .{ .x86_64 = .@"32" },
804 ) else if (emit.bin_file.cast(.coff)) |coff_file| {
773 const atom_index = coff_file.getAtomIndexForSymbol(805 const atom_index = coff_file.getAtomIndexForSymbol(
774 .{ .sym_index = emit.atom_index, .file = null },806 .{ .sym_index = emit.atom_index, .file = null },
775 ).?;807 ).?;
...@@ -794,7 +826,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -794,7 +826,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
794 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),826 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),
795 .r_addend = reloc.off - 4,827 .r_addend = reloc.off - 4,
796 }, zo);828 }, zo);
797 } else if (emit.bin_file.cast(.macho)) |macho_file| {829 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
830 @enumFromInt(emit.atom_index),
831 end_offset - 4,
832 @enumFromInt(reloc.target.index),
833 reloc.off - 4,
834 .{ .x86_64 = .PC32 },
835 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
798 const zo = macho_file.getZigObject().?;836 const zo = macho_file.getZigObject().?;
799 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;837 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
800 try atom.addReloc(macho_file, .{838 try atom.addReloc(macho_file, .{
...@@ -849,7 +887,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI...@@ -849,7 +887,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI
849 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),887 .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type),
850 .r_addend = reloc.off,888 .r_addend = reloc.off,
851 }, zo);889 }, zo);
852 } else if (emit.bin_file.cast(.macho)) |macho_file| {890 } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc(
891 @enumFromInt(emit.atom_index),
892 end_offset - 4,
893 @enumFromInt(reloc.target.index),
894 reloc.off,
895 .{ .x86_64 = .TPOFF32 },
896 ) else if (emit.bin_file.cast(.macho)) |macho_file| {
853 const zo = macho_file.getZigObject().?;897 const zo = macho_file.getZigObject().?;
854 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;898 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
855 try atom.addReloc(macho_file, .{899 try atom.addReloc(macho_file, .{
...@@ -908,7 +952,7 @@ const Loc = struct {...@@ -908,7 +952,7 @@ const Loc = struct {
908952
909fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void {953fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void {
910 const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line);954 const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line);
911 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;955 const delta_pc: usize = emit.w.end - emit.prev_di_pc;
912 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });956 log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line });
913 switch (emit.debug_output) {957 switch (emit.debug_output) {
914 .dwarf => |dwarf| {958 .dwarf => |dwarf| {
...@@ -916,7 +960,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void {...@@ -916,7 +960,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void {
916 if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column);960 if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column);
917 try dwarf.advancePCAndLine(delta_line, delta_pc);961 try dwarf.advancePCAndLine(delta_line, delta_pc);
918 emit.prev_di_loc = loc;962 emit.prev_di_loc = loc;
919 emit.prev_di_pc = emit.code.items.len;963 emit.prev_di_pc = emit.w.end;
920 },964 },
921 .none => {},965 .none => {},
922 }966 }
src/arch/x86_64/Mir.zig+8-25
...@@ -1976,7 +1976,8 @@ pub fn emit(...@@ -1976,7 +1976,8 @@ pub fn emit(
1976 pt: Zcu.PerThread,1976 pt: Zcu.PerThread,
1977 src_loc: Zcu.LazySrcLoc,1977 src_loc: Zcu.LazySrcLoc,
1978 func_index: InternPool.Index,1978 func_index: InternPool.Index,
1979 code: *std.ArrayListUnmanaged(u8),1979 atom_index: u32,
1980 w: *std.Io.Writer,
1980 debug_output: link.File.DebugInfoOutput,1981 debug_output: link.File.DebugInfoOutput,
1981) codegen.CodeGenError!void {1982) codegen.CodeGenError!void {
1982 const zcu = pt.zcu;1983 const zcu = pt.zcu;
...@@ -1997,17 +1998,9 @@ pub fn emit(...@@ -1997,17 +1998,9 @@ pub fn emit(
1997 .bin_file = lf,1998 .bin_file = lf,
1998 .pt = pt,1999 .pt = pt,
1999 .pic = mod.pic,2000 .pic = mod.pic,
2000 .atom_index = sym: {2001 .atom_index = atom_index,
2001 if (lf.cast(.elf)) |ef| break :sym try ef.zigObjectPtr().?.getOrCreateMetadataForNav(zcu, nav);
2002 if (lf.cast(.macho)) |mf| break :sym try mf.getZigObject().?.getOrCreateMetadataForNav(mf, nav);
2003 if (lf.cast(.coff)) |cf| {
2004 const atom = try cf.getOrCreateAtomForNav(nav);
2005 break :sym cf.getAtom(atom).getSymbolIndex().?;
2006 }
2007 unreachable;
2008 },
2009 .debug_output = debug_output,2002 .debug_output = debug_output,
2010 .code = code,2003 .w = w,
20112004
2012 .prev_di_loc = .{2005 .prev_di_loc = .{
2013 .line = func.lbrace_line,2006 .line = func.lbrace_line,
...@@ -2037,7 +2030,8 @@ pub fn emitLazy(...@@ -2037,7 +2030,8 @@ pub fn emitLazy(
2037 pt: Zcu.PerThread,2030 pt: Zcu.PerThread,
2038 src_loc: Zcu.LazySrcLoc,2031 src_loc: Zcu.LazySrcLoc,
2039 lazy_sym: link.File.LazySymbol,2032 lazy_sym: link.File.LazySymbol,
2040 code: *std.ArrayListUnmanaged(u8),2033 atom_index: u32,
2034 w: *std.Io.Writer,
2041 debug_output: link.File.DebugInfoOutput,2035 debug_output: link.File.DebugInfoOutput,
2042) codegen.CodeGenError!void {2036) codegen.CodeGenError!void {
2043 const zcu = pt.zcu;2037 const zcu = pt.zcu;
...@@ -2055,20 +2049,9 @@ pub fn emitLazy(...@@ -2055,20 +2049,9 @@ pub fn emitLazy(
2055 .bin_file = lf,2049 .bin_file = lf,
2056 .pt = pt,2050 .pt = pt,
2057 .pic = mod.pic,2051 .pic = mod.pic,
2058 .atom_index = sym: {2052 .atom_index = atom_index,
2059 if (lf.cast(.elf)) |ef| break :sym ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_sym) catch |err|
2060 return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)});
2061 if (lf.cast(.macho)) |mf| break :sym mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_sym) catch |err|
2062 return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)});
2063 if (lf.cast(.coff)) |cf| {
2064 const atom = cf.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
2065 return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)});
2066 break :sym cf.getAtom(atom).getSymbolIndex().?;
2067 }
2068 unreachable;
2069 },
2070 .debug_output = debug_output,2053 .debug_output = debug_output,
2071 .code = code,2054 .w = w,
20722055
2073 .prev_di_loc = undefined,2056 .prev_di_loc = undefined,
2074 .prev_di_pc = undefined,2057 .prev_di_pc = undefined,
src/arch/x86_64/bits.zig+8
...@@ -727,6 +727,14 @@ pub const FrameIndex = enum(u32) {...@@ -727,6 +727,14 @@ pub const FrameIndex = enum(u32) {
727 pub fn isNamed(fi: FrameIndex) bool {727 pub fn isNamed(fi: FrameIndex) bool {
728 return @intFromEnum(fi) < named_count;728 return @intFromEnum(fi) < named_count;
729 }729 }
730
731 pub fn format(fi: FrameIndex, writer: *std.Io.Writer) std.Io.Writer.Error!void {
732 if (fi.isNamed()) {
733 try writer.print("FrameIndex.{t}", .{fi});
734 } else {
735 try writer.print("FrameIndex({d})", .{@intFromEnum(fi)});
736 }
737 }
730};738};
731739
732pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };740pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 };
src/arch/x86_64/encoder.zig+1-1
...@@ -259,7 +259,7 @@ pub const Instruction = struct {...@@ -259,7 +259,7 @@ pub const Instruction = struct {
259 switch (sib.base) {259 switch (sib.base) {
260 .none => any = false,260 .none => any = false,
261 .reg => |reg| try w.print("{s}", .{@tagName(reg)}),261 .reg => |reg| try w.print("{s}", .{@tagName(reg)}),
262 .frame => |frame_index| try w.print("{}", .{frame_index}),262 .frame => |frame_index| try w.print("{f}", .{frame_index}),
263 .table => try w.print("Table", .{}),263 .table => try w.print("Table", .{}),
264 .rip_inst => |inst_index| try w.print("RipInst({d})", .{inst_index}),264 .rip_inst => |inst_index| try w.print("RipInst({d})", .{inst_index}),
265 .nav => |nav| try w.print("Nav({d})", .{@intFromEnum(nav)}),265 .nav => |nav| try w.print("Nav({d})", .{@intFromEnum(nav)}),
src/codegen.zig+133-138
...@@ -6,7 +6,6 @@ const link = @import("link.zig");...@@ -6,7 +6,6 @@ const link = @import("link.zig");
6const log = std.log.scoped(.codegen);6const log = std.log.scoped(.codegen);
7const mem = std.mem;7const mem = std.mem;
8const math = std.math;8const math = std.math;
9const ArrayList = std.ArrayList;
10const target_util = @import("target.zig");9const target_util = @import("target.zig");
11const trace = @import("tracy.zig").trace;10const trace = @import("tracy.zig").trace;
1211
...@@ -179,10 +178,11 @@ pub fn emitFunction(...@@ -179,10 +178,11 @@ pub fn emitFunction(
179 pt: Zcu.PerThread,178 pt: Zcu.PerThread,
180 src_loc: Zcu.LazySrcLoc,179 src_loc: Zcu.LazySrcLoc,
181 func_index: InternPool.Index,180 func_index: InternPool.Index,
181 atom_index: u32,
182 any_mir: *const AnyMir,182 any_mir: *const AnyMir,
183 code: *ArrayList(u8),183 w: *std.Io.Writer,
184 debug_output: link.File.DebugInfoOutput,184 debug_output: link.File.DebugInfoOutput,
185) CodeGenError!void {185) (CodeGenError || std.Io.Writer.Error)!void {
186 const zcu = pt.zcu;186 const zcu = pt.zcu;
187 const func = zcu.funcInfo(func_index);187 const func = zcu.funcInfo(func_index);
188 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;188 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
...@@ -195,7 +195,7 @@ pub fn emitFunction(...@@ -195,7 +195,7 @@ pub fn emitFunction(
195 => |backend| {195 => |backend| {
196 dev.check(devFeatureForBackend(backend));196 dev.check(devFeatureForBackend(backend));
197 const mir = &@field(any_mir, AnyMir.tag(backend));197 const mir = &@field(any_mir, AnyMir.tag(backend));
198 return mir.emit(lf, pt, src_loc, func_index, code, debug_output);198 return mir.emit(lf, pt, src_loc, func_index, atom_index, w, debug_output);
199 },199 },
200 }200 }
201}201}
...@@ -205,9 +205,10 @@ pub fn generateLazyFunction(...@@ -205,9 +205,10 @@ pub fn generateLazyFunction(
205 pt: Zcu.PerThread,205 pt: Zcu.PerThread,
206 src_loc: Zcu.LazySrcLoc,206 src_loc: Zcu.LazySrcLoc,
207 lazy_sym: link.File.LazySymbol,207 lazy_sym: link.File.LazySymbol,
208 code: *ArrayList(u8),208 atom_index: u32,
209 w: *std.Io.Writer,
209 debug_output: link.File.DebugInfoOutput,210 debug_output: link.File.DebugInfoOutput,
210) CodeGenError!void {211) (CodeGenError || std.Io.Writer.Error)!void {
211 const zcu = pt.zcu;212 const zcu = pt.zcu;
212 const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index|213 const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index|
213 &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result214 &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result
...@@ -217,19 +218,11 @@ pub fn generateLazyFunction(...@@ -217,19 +218,11 @@ pub fn generateLazyFunction(
217 else => unreachable,218 else => unreachable,
218 inline .stage2_riscv64, .stage2_x86_64 => |backend| {219 inline .stage2_riscv64, .stage2_x86_64 => |backend| {
219 dev.check(devFeatureForBackend(backend));220 dev.check(devFeatureForBackend(backend));
220 return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, code, debug_output);221 return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, atom_index, w, debug_output);
221 },222 },
222 }223 }
223}224}
224225
225fn writeFloat(comptime F: type, f: F, target: *const std.Target, endian: std.builtin.Endian, code: []u8) void {
226 _ = target;
227 const bits = @typeInfo(F).float.bits;
228 const Int = @Type(.{ .int = .{ .signedness = .unsigned, .bits = bits } });
229 const int: Int = @bitCast(f);
230 mem.writeInt(Int, code[0..@divExact(bits, 8)], int, endian);
231}
232
233pub fn generateLazySymbol(226pub fn generateLazySymbol(
234 bin_file: *link.File,227 bin_file: *link.File,
235 pt: Zcu.PerThread,228 pt: Zcu.PerThread,
...@@ -237,17 +230,14 @@ pub fn generateLazySymbol(...@@ -237,17 +230,14 @@ pub fn generateLazySymbol(
237 lazy_sym: link.File.LazySymbol,230 lazy_sym: link.File.LazySymbol,
238 // TODO don't use an "out" parameter like this; put it in the result instead231 // TODO don't use an "out" parameter like this; put it in the result instead
239 alignment: *Alignment,232 alignment: *Alignment,
240 code: *ArrayList(u8),233 w: *std.Io.Writer,
241 debug_output: link.File.DebugInfoOutput,234 debug_output: link.File.DebugInfoOutput,
242 reloc_parent: link.File.RelocInfo.Parent,235 reloc_parent: link.File.RelocInfo.Parent,
243) CodeGenError!void {236) (CodeGenError || std.Io.Writer.Error)!void {
244 _ = reloc_parent;
245
246 const tracy = trace(@src());237 const tracy = trace(@src());
247 defer tracy.end();238 defer tracy.end();
248239
249 const comp = bin_file.comp;240 const comp = bin_file.comp;
250 const gpa = comp.gpa;
251 const zcu = pt.zcu;241 const zcu = pt.zcu;
252 const ip = &zcu.intern_pool;242 const ip = &zcu.intern_pool;
253 const target = &comp.root_mod.resolved_target.result;243 const target = &comp.root_mod.resolved_target.result;
...@@ -260,37 +250,36 @@ pub fn generateLazySymbol(...@@ -260,37 +250,36 @@ pub fn generateLazySymbol(
260250
261 if (lazy_sym.kind == .code) {251 if (lazy_sym.kind == .code) {
262 alignment.* = target_util.defaultFunctionAlignment(target);252 alignment.* = target_util.defaultFunctionAlignment(target);
263 return generateLazyFunction(bin_file, pt, src_loc, lazy_sym, code, debug_output);253 return generateLazyFunction(bin_file, pt, src_loc, lazy_sym, reloc_parent.atom_index, w, debug_output);
264 }254 }
265255
266 if (lazy_sym.ty == .anyerror_type) {256 if (lazy_sym.ty == .anyerror_type) {
267 alignment.* = .@"4";257 alignment.* = .@"4";
268 const err_names = ip.global_error_set.getNamesFromMainThread();258 const err_names = ip.global_error_set.getNamesFromMainThread();
269 var offset_index: u32 = @intCast(code.items.len);259 const strings_start: u32 = @intCast(4 * (1 + err_names.len + @intFromBool(err_names.len > 0)));
270 var string_index: u32 = @intCast(4 * (1 + err_names.len + @intFromBool(err_names.len > 0)));260 var string_index = strings_start;
271 try code.resize(gpa, offset_index + string_index);261 try w.rebase(w.end, string_index);
272 mem.writeInt(u32, code.items[offset_index..][0..4], @intCast(err_names.len), endian);262 w.writeInt(u32, @intCast(err_names.len), endian) catch unreachable;
273 if (err_names.len == 0) return;263 if (err_names.len == 0) return;
274 offset_index += 4;
275 for (err_names) |err_name_nts| {264 for (err_names) |err_name_nts| {
276 const err_name = err_name_nts.toSlice(ip);265 w.writeInt(u32, string_index, endian) catch unreachable;
277 mem.writeInt(u32, code.items[offset_index..][0..4], string_index, endian);266 string_index += @intCast(err_name_nts.toSlice(ip).len + 1);
278 offset_index += 4;267 }
279 try code.ensureUnusedCapacity(gpa, err_name.len + 1);268 w.writeInt(u32, string_index, endian) catch unreachable;
280 code.appendSliceAssumeCapacity(err_name);269 try w.rebase(w.end, string_index - strings_start);
281 code.appendAssumeCapacity(0);270 for (err_names) |err_name_nts| {
282 string_index += @intCast(err_name.len + 1);271 w.writeAll(err_name_nts.toSlice(ip)) catch unreachable;
272 w.writeByte(0) catch unreachable;
283 }273 }
284 mem.writeInt(u32, code.items[offset_index..][0..4], string_index, endian);
285 } else if (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu) == .@"enum") {274 } else if (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu) == .@"enum") {
286 alignment.* = .@"1";275 alignment.* = .@"1";
287 const enum_ty = Type.fromInterned(lazy_sym.ty);276 const enum_ty = Type.fromInterned(lazy_sym.ty);
288 const tag_names = enum_ty.enumFields(zcu);277 const tag_names = enum_ty.enumFields(zcu);
289 for (0..tag_names.len) |tag_index| {278 for (0..tag_names.len) |tag_index| {
290 const tag_name = tag_names.get(ip)[tag_index].toSlice(ip);279 const tag_name = tag_names.get(ip)[tag_index].toSlice(ip);
291 try code.ensureUnusedCapacity(gpa, tag_name.len + 1);280 try w.rebase(w.end, tag_name.len + 1);
292 code.appendSliceAssumeCapacity(tag_name);281 w.writeAll(tag_name) catch unreachable;
293 code.appendAssumeCapacity(0);282 w.writeByte(0) catch unreachable;
294 }283 }
295 } else {284 } else {
296 return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{285 return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{
...@@ -312,14 +301,13 @@ pub fn generateSymbol(...@@ -312,14 +301,13 @@ pub fn generateSymbol(
312 pt: Zcu.PerThread,301 pt: Zcu.PerThread,
313 src_loc: Zcu.LazySrcLoc,302 src_loc: Zcu.LazySrcLoc,
314 val: Value,303 val: Value,
315 code: *ArrayList(u8),304 w: *std.Io.Writer,
316 reloc_parent: link.File.RelocInfo.Parent,305 reloc_parent: link.File.RelocInfo.Parent,
317) GenerateSymbolError!void {306) (GenerateSymbolError || std.Io.Writer.Error)!void {
318 const tracy = trace(@src());307 const tracy = trace(@src());
319 defer tracy.end();308 defer tracy.end();
320309
321 const zcu = pt.zcu;310 const zcu = pt.zcu;
322 const gpa = zcu.gpa;
323 const ip = &zcu.intern_pool;311 const ip = &zcu.intern_pool;
324 const ty = val.typeOf(zcu);312 const ty = val.typeOf(zcu);
325313
...@@ -330,7 +318,7 @@ pub fn generateSymbol(...@@ -330,7 +318,7 @@ pub fn generateSymbol(
330318
331 if (val.isUndef(zcu)) {319 if (val.isUndef(zcu)) {
332 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;320 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
333 try code.appendNTimes(gpa, 0xaa, abi_size);321 try w.splatByteAll(0xaa, abi_size);
334 return;322 return;
335 }323 }
336324
...@@ -360,7 +348,7 @@ pub fn generateSymbol(...@@ -360,7 +348,7 @@ pub fn generateSymbol(
360 .null => unreachable, // non-runtime value348 .null => unreachable, // non-runtime value
361 .@"unreachable" => unreachable, // non-runtime value349 .@"unreachable" => unreachable, // non-runtime value
362 .empty_tuple => return,350 .empty_tuple => return,
363 .false, .true => try code.append(gpa, switch (simple_value) {351 .false, .true => try w.writeByte(switch (simple_value) {
364 .false => 0,352 .false => 0,
365 .true => 1,353 .true => 1,
366 else => unreachable,354 else => unreachable,
...@@ -376,11 +364,11 @@ pub fn generateSymbol(...@@ -376,11 +364,11 @@ pub fn generateSymbol(
376 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;364 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
377 var space: Value.BigIntSpace = undefined;365 var space: Value.BigIntSpace = undefined;
378 const int_val = val.toBigInt(&space, zcu);366 const int_val = val.toBigInt(&space, zcu);
379 int_val.writeTwosComplement(try code.addManyAsSlice(gpa, abi_size), endian);367 int_val.writeTwosComplement(try w.writableSlice(abi_size), endian);
380 },368 },
381 .err => |err| {369 .err => |err| {
382 const int = try pt.getErrorValue(err.name);370 const int = try pt.getErrorValue(err.name);
383 mem.writeInt(u16, try code.addManyAsArray(gpa, 2), @intCast(int), endian);371 try w.writeInt(u16, @intCast(int), endian);
384 },372 },
385 .error_union => |error_union| {373 .error_union => |error_union| {
386 const payload_ty = ty.errorUnionPayload(zcu);374 const payload_ty = ty.errorUnionPayload(zcu);
...@@ -390,7 +378,7 @@ pub fn generateSymbol(...@@ -390,7 +378,7 @@ pub fn generateSymbol(
390 };378 };
391379
392 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {380 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
393 mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian);381 try w.writeInt(u16, err_val, endian);
394 return;382 return;
395 }383 }
396384
...@@ -400,63 +388,63 @@ pub fn generateSymbol(...@@ -400,63 +388,63 @@ pub fn generateSymbol(
400388
401 // error value first when its type is larger than the error union's payload389 // error value first when its type is larger than the error union's payload
402 if (error_align.order(payload_align) == .gt) {390 if (error_align.order(payload_align) == .gt) {
403 mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian);391 try w.writeInt(u16, err_val, endian);
404 }392 }
405393
406 // emit payload part of the error union394 // emit payload part of the error union
407 {395 {
408 const begin = code.items.len;396 const begin = w.end;
409 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (error_union.val) {397 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (error_union.val) {
410 .err_name => try pt.intern(.{ .undef = payload_ty.toIntern() }),398 .err_name => try pt.intern(.{ .undef = payload_ty.toIntern() }),
411 .payload => |payload| payload,399 .payload => |payload| payload,
412 }), code, reloc_parent);400 }), w, reloc_parent);
413 const unpadded_end = code.items.len - begin;401 const unpadded_end = w.end - begin;
414 const padded_end = abi_align.forward(unpadded_end);402 const padded_end = abi_align.forward(unpadded_end);
415 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;403 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;
416404
417 if (padding > 0) {405 if (padding > 0) {
418 try code.appendNTimes(gpa, 0, padding);406 try w.splatByteAll(0, padding);
419 }407 }
420 }408 }
421409
422 // Payload size is larger than error set, so emit our error set last410 // Payload size is larger than error set, so emit our error set last
423 if (error_align.compare(.lte, payload_align)) {411 if (error_align.compare(.lte, payload_align)) {
424 const begin = code.items.len;412 const begin = w.end;
425 mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian);413 try w.writeInt(u16, err_val, endian);
426 const unpadded_end = code.items.len - begin;414 const unpadded_end = w.end - begin;
427 const padded_end = abi_align.forward(unpadded_end);415 const padded_end = abi_align.forward(unpadded_end);
428 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;416 const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow;
429417
430 if (padding > 0) {418 if (padding > 0) {
431 try code.appendNTimes(gpa, 0, padding);419 try w.splatByteAll(0, padding);
432 }420 }
433 }421 }
434 },422 },
435 .enum_tag => |enum_tag| {423 .enum_tag => |enum_tag| {
436 const int_tag_ty = ty.intTagType(zcu);424 const int_tag_ty = ty.intTagType(zcu);
437 try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent);425 try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), w, reloc_parent);
438 },426 },
439 .float => |float| storage: switch (float.storage) {427 .float => |float| storage: switch (float.storage) {
440 .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)),428 .f16 => |f16_val| try w.writeInt(u16, @bitCast(f16_val), endian),
441 .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)),429 .f32 => |f32_val| try w.writeInt(u32, @bitCast(f32_val), endian),
442 .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)),430 .f64 => |f64_val| try w.writeInt(u64, @bitCast(f64_val), endian),
443 .f80 => |f80_val| {431 .f80 => |f80_val| {
444 writeFloat(f80, f80_val, target, endian, try code.addManyAsArray(gpa, 10));432 try w.writeInt(u80, @bitCast(f80_val), endian);
445 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;433 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
446 try code.appendNTimes(gpa, 0, abi_size - 10);434 try w.splatByteAll(0, abi_size - 10);
447 },435 },
448 .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) {436 .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) {
449 else => unreachable,437 else => unreachable,
450 16 => continue :storage .{ .f16 = @floatCast(f128_val) },438 16 => continue :storage .{ .f16 = @floatCast(f128_val) },
451 32 => continue :storage .{ .f32 = @floatCast(f128_val) },439 32 => continue :storage .{ .f32 = @floatCast(f128_val) },
452 64 => continue :storage .{ .f64 = @floatCast(f128_val) },440 64 => continue :storage .{ .f64 = @floatCast(f128_val) },
453 128 => writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)),441 128 => try w.writeInt(u128, @bitCast(f128_val), endian),
454 },442 },
455 },443 },
456 .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0),444 .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), w, reloc_parent, 0),
457 .slice => |slice| {445 .slice => |slice| {
458 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), code, reloc_parent);446 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), w, reloc_parent);
459 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), code, reloc_parent);447 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), w, reloc_parent);
460 },448 },
461 .opt => {449 .opt => {
462 const payload_type = ty.optionalChild(zcu);450 const payload_type = ty.optionalChild(zcu);
...@@ -465,9 +453,9 @@ pub fn generateSymbol(...@@ -465,9 +453,9 @@ pub fn generateSymbol(
465453
466 if (ty.optionalReprIsPayload(zcu)) {454 if (ty.optionalReprIsPayload(zcu)) {
467 if (payload_val) |value| {455 if (payload_val) |value| {
468 try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent);456 try generateSymbol(bin_file, pt, src_loc, value, w, reloc_parent);
469 } else {457 } else {
470 try code.appendNTimes(gpa, 0, abi_size);458 try w.splatByteAll(0, abi_size);
471 }459 }
472 } else {460 } else {
473 const padding = abi_size - (math.cast(usize, payload_type.abiSize(zcu)) orelse return error.Overflow) - 1;461 const padding = abi_size - (math.cast(usize, payload_type.abiSize(zcu)) orelse return error.Overflow) - 1;
...@@ -475,15 +463,15 @@ pub fn generateSymbol(...@@ -475,15 +463,15 @@ pub fn generateSymbol(
475 const value = payload_val orelse Value.fromInterned(try pt.intern(.{463 const value = payload_val orelse Value.fromInterned(try pt.intern(.{
476 .undef = payload_type.toIntern(),464 .undef = payload_type.toIntern(),
477 }));465 }));
478 try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent);466 try generateSymbol(bin_file, pt, src_loc, value, w, reloc_parent);
479 }467 }
480 try code.append(gpa, @intFromBool(payload_val != null));468 try w.writeByte(@intFromBool(payload_val != null));
481 try code.appendNTimes(gpa, 0, padding);469 try w.splatByteAll(0, padding);
482 }470 }
483 },471 },
484 .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) {472 .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) {
485 .array_type => |array_type| switch (aggregate.storage) {473 .array_type => |array_type| switch (aggregate.storage) {
486 .bytes => |bytes| try code.appendSlice(gpa, bytes.toSlice(array_type.lenIncludingSentinel(), ip)),474 .bytes => |bytes| try w.writeAll(bytes.toSlice(array_type.lenIncludingSentinel(), ip)),
487 .elems, .repeated_elem => {475 .elems, .repeated_elem => {
488 var index: u64 = 0;476 var index: u64 = 0;
489 while (index < array_type.lenIncludingSentinel()) : (index += 1) {477 while (index < array_type.lenIncludingSentinel()) : (index += 1) {
...@@ -494,14 +482,14 @@ pub fn generateSymbol(...@@ -494,14 +482,14 @@ pub fn generateSymbol(
494 elem482 elem
495 else483 else
496 array_type.sentinel,484 array_type.sentinel,
497 }), code, reloc_parent);485 }), w, reloc_parent);
498 }486 }
499 },487 },
500 },488 },
501 .vector_type => |vector_type| {489 .vector_type => |vector_type| {
502 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;490 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
503 if (vector_type.child == .bool_type) {491 if (vector_type.child == .bool_type) {
504 const bytes = try code.addManyAsSlice(gpa, abi_size);492 const bytes = try w.writableSlice(abi_size);
505 @memset(bytes, 0xaa);493 @memset(bytes, 0xaa);
506 var index: usize = 0;494 var index: usize = 0;
507 const len = math.cast(usize, vector_type.len) orelse return error.Overflow;495 const len = math.cast(usize, vector_type.len) orelse return error.Overflow;
...@@ -540,7 +528,7 @@ pub fn generateSymbol(...@@ -540,7 +528,7 @@ pub fn generateSymbol(
540 }528 }
541 } else {529 } else {
542 switch (aggregate.storage) {530 switch (aggregate.storage) {
543 .bytes => |bytes| try code.appendSlice(gpa, bytes.toSlice(vector_type.len, ip)),531 .bytes => |bytes| try w.writeAll(bytes.toSlice(vector_type.len, ip)),
544 .elems, .repeated_elem => {532 .elems, .repeated_elem => {
545 var index: u64 = 0;533 var index: u64 = 0;
546 while (index < vector_type.len) : (index += 1) {534 while (index < vector_type.len) : (index += 1) {
...@@ -550,7 +538,7 @@ pub fn generateSymbol(...@@ -550,7 +538,7 @@ pub fn generateSymbol(
550 math.cast(usize, index) orelse return error.Overflow538 math.cast(usize, index) orelse return error.Overflow
551 ],539 ],
552 .repeated_elem => |elem| elem,540 .repeated_elem => |elem| elem,
553 }), code, reloc_parent);541 }), w, reloc_parent);
554 }542 }
555 },543 },
556 }544 }
...@@ -558,11 +546,11 @@ pub fn generateSymbol(...@@ -558,11 +546,11 @@ pub fn generateSymbol(
558 const padding = abi_size -546 const padding = abi_size -
559 (math.cast(usize, Type.fromInterned(vector_type.child).abiSize(zcu) * vector_type.len) orelse547 (math.cast(usize, Type.fromInterned(vector_type.child).abiSize(zcu) * vector_type.len) orelse
560 return error.Overflow);548 return error.Overflow);
561 if (padding > 0) try code.appendNTimes(gpa, 0, padding);549 if (padding > 0) try w.splatByteAll(0, padding);
562 }550 }
563 },551 },
564 .tuple_type => |tuple| {552 .tuple_type => |tuple| {
565 const struct_begin = code.items.len;553 const struct_begin = w.end;
566 for (554 for (
567 tuple.types.get(ip),555 tuple.types.get(ip),
568 tuple.values.get(ip),556 tuple.values.get(ip),
...@@ -580,8 +568,8 @@ pub fn generateSymbol(...@@ -580,8 +568,8 @@ pub fn generateSymbol(
580 .repeated_elem => |elem| elem,568 .repeated_elem => |elem| elem,
581 };569 };
582570
583 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent);571 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent);
584 const unpadded_field_end = code.items.len - struct_begin;572 const unpadded_field_end = w.end - struct_begin;
585573
586 // Pad struct members if required574 // Pad struct members if required
587 const padded_field_end = ty.structFieldOffset(index + 1, zcu);575 const padded_field_end = ty.structFieldOffset(index + 1, zcu);
...@@ -589,7 +577,7 @@ pub fn generateSymbol(...@@ -589,7 +577,7 @@ pub fn generateSymbol(
589 return error.Overflow;577 return error.Overflow;
590578
591 if (padding > 0) {579 if (padding > 0) {
592 try code.appendNTimes(gpa, 0, padding);580 try w.splatByteAll(0, padding);
593 }581 }
594 }582 }
595 },583 },
...@@ -598,8 +586,9 @@ pub fn generateSymbol(...@@ -598,8 +586,9 @@ pub fn generateSymbol(
598 switch (struct_type.layout) {586 switch (struct_type.layout) {
599 .@"packed" => {587 .@"packed" => {
600 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;588 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
601 const current_pos = code.items.len;589 const start = w.end;
602 try code.appendNTimes(gpa, 0, abi_size);590 const buffer = try w.writableSlice(abi_size);
591 @memset(buffer, 0);
603 var bits: u16 = 0;592 var bits: u16 = 0;
604593
605 for (struct_type.field_types.get(ip), 0..) |field_ty, index| {594 for (struct_type.field_types.get(ip), 0..) |field_ty, index| {
...@@ -619,22 +608,20 @@ pub fn generateSymbol(...@@ -619,22 +608,20 @@ pub fn generateSymbol(
619 error.DivisionByZero => unreachable,608 error.DivisionByZero => unreachable,
620 error.UnexpectedRemainder => return error.RelocationNotByteAligned,609 error.UnexpectedRemainder => return error.RelocationNotByteAligned,
621 };610 };
622 code.items.len = current_pos + field_offset;611 w.end = start + field_offset;
623 // TODO: code.lockPointers();
624 defer {612 defer {
625 assert(code.items.len == current_pos + field_offset + @divExact(target.ptrBitWidth(), 8));613 assert(w.end == start + field_offset + @divExact(target.ptrBitWidth(), 8));
626 // TODO: code.unlockPointers();614 w.end = start + abi_size;
627 code.items.len = current_pos + abi_size;
628 }615 }
629 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent);616 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent);
630 } else {617 } else {
631 Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), pt, code.items[current_pos..], bits) catch unreachable;618 Value.fromInterned(field_val).writeToPackedMemory(.fromInterned(field_ty), pt, buffer, bits) catch unreachable;
632 }619 }
633 bits += @intCast(Type.fromInterned(field_ty).bitSize(zcu));620 bits += @intCast(Type.fromInterned(field_ty).bitSize(zcu));
634 }621 }
635 },622 },
636 .auto, .@"extern" => {623 .auto, .@"extern" => {
637 const struct_begin = code.items.len;624 const struct_begin = w.end;
638 const field_types = struct_type.field_types.get(ip);625 const field_types = struct_type.field_types.get(ip);
639 const offsets = struct_type.offsets.get(ip);626 const offsets = struct_type.offsets.get(ip);
640627
...@@ -654,11 +641,11 @@ pub fn generateSymbol(...@@ -654,11 +641,11 @@ pub fn generateSymbol(
654641
655 const padding = math.cast(642 const padding = math.cast(
656 usize,643 usize,
657 offsets[field_index] - (code.items.len - struct_begin),644 offsets[field_index] - (w.end - struct_begin),
658 ) orelse return error.Overflow;645 ) orelse return error.Overflow;
659 if (padding > 0) try code.appendNTimes(gpa, 0, padding);646 if (padding > 0) try w.splatByteAll(0, padding);
660647
661 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent);648 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent);
662 }649 }
663650
664 const size = struct_type.sizeUnordered(ip);651 const size = struct_type.sizeUnordered(ip);
...@@ -666,10 +653,9 @@ pub fn generateSymbol(...@@ -666,10 +653,9 @@ pub fn generateSymbol(
666653
667 const padding = math.cast(654 const padding = math.cast(
668 usize,655 usize,
669 std.mem.alignForward(u64, size, @max(alignment, 1)) -656 std.mem.alignForward(u64, size, @max(alignment, 1)) - (w.end - struct_begin),
670 (code.items.len - struct_begin),
671 ) orelse return error.Overflow;657 ) orelse return error.Overflow;
672 if (padding > 0) try code.appendNTimes(gpa, 0, padding);658 if (padding > 0) try w.splatByteAll(0, padding);
673 },659 },
674 }660 }
675 },661 },
...@@ -679,12 +665,12 @@ pub fn generateSymbol(...@@ -679,12 +665,12 @@ pub fn generateSymbol(
679 const layout = ty.unionGetLayout(zcu);665 const layout = ty.unionGetLayout(zcu);
680666
681 if (layout.payload_size == 0) {667 if (layout.payload_size == 0) {
682 return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent);668 return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent);
683 }669 }
684670
685 // Check if we should store the tag first.671 // Check if we should store the tag first.
686 if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) {672 if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) {
687 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent);673 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent);
688 }674 }
689675
690 const union_obj = zcu.typeToUnion(ty).?;676 const union_obj = zcu.typeToUnion(ty).?;
...@@ -692,24 +678,24 @@ pub fn generateSymbol(...@@ -692,24 +678,24 @@ pub fn generateSymbol(
692 const field_index = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?;678 const field_index = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
693 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);679 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
694 if (!field_ty.hasRuntimeBits(zcu)) {680 if (!field_ty.hasRuntimeBits(zcu)) {
695 try code.appendNTimes(gpa, 0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);681 try w.splatByteAll(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow);
696 } else {682 } else {
697 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent);683 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), w, reloc_parent);
698684
699 const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(zcu)) orelse return error.Overflow;685 const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(zcu)) orelse return error.Overflow;
700 if (padding > 0) {686 if (padding > 0) {
701 try code.appendNTimes(gpa, 0, padding);687 try w.splatByteAll(0, padding);
702 }688 }
703 }689 }
704 } else {690 } else {
705 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent);691 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), w, reloc_parent);
706 }692 }
707693
708 if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) {694 if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) {
709 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent);695 try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent);
710696
711 if (layout.padding > 0) {697 if (layout.padding > 0) {
712 try code.appendNTimes(gpa, 0, layout.padding);698 try w.splatByteAll(0, layout.padding);
713 }699 }
714 }700 }
715 },701 },
...@@ -722,30 +708,30 @@ fn lowerPtr(...@@ -722,30 +708,30 @@ fn lowerPtr(
722 pt: Zcu.PerThread,708 pt: Zcu.PerThread,
723 src_loc: Zcu.LazySrcLoc,709 src_loc: Zcu.LazySrcLoc,
724 ptr_val: InternPool.Index,710 ptr_val: InternPool.Index,
725 code: *ArrayList(u8),711 w: *std.Io.Writer,
726 reloc_parent: link.File.RelocInfo.Parent,712 reloc_parent: link.File.RelocInfo.Parent,
727 prev_offset: u64,713 prev_offset: u64,
728) GenerateSymbolError!void {714) (GenerateSymbolError || std.Io.Writer.Error)!void {
729 const zcu = pt.zcu;715 const zcu = pt.zcu;
730 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;716 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
731 const offset: u64 = prev_offset + ptr.byte_offset;717 const offset: u64 = prev_offset + ptr.byte_offset;
732 return switch (ptr.base_addr) {718 return switch (ptr.base_addr) {
733 .nav => |nav| try lowerNavRef(bin_file, pt, nav, code, reloc_parent, offset),719 .nav => |nav| try lowerNavRef(bin_file, pt, nav, w, reloc_parent, offset),
734 .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, code, reloc_parent, offset),720 .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, w, reloc_parent, offset),
735 .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), code, reloc_parent),721 .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), w, reloc_parent),
736 .eu_payload => |eu_ptr| try lowerPtr(722 .eu_payload => |eu_ptr| try lowerPtr(
737 bin_file,723 bin_file,
738 pt,724 pt,
739 src_loc,725 src_loc,
740 eu_ptr,726 eu_ptr,
741 code,727 w,
742 reloc_parent,728 reloc_parent,
743 offset + errUnionPayloadOffset(729 offset + errUnionPayloadOffset(
744 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu).errorUnionPayload(zcu),730 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu).errorUnionPayload(zcu),
745 zcu,731 zcu,
746 ),732 ),
747 ),733 ),
748 .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, code, reloc_parent, offset),734 .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, w, reloc_parent, offset),
749 .field => |field| {735 .field => |field| {
750 const base_ptr = Value.fromInterned(field.base);736 const base_ptr = Value.fromInterned(field.base);
751 const base_ty = base_ptr.typeOf(zcu).childType(zcu);737 const base_ty = base_ptr.typeOf(zcu).childType(zcu);
...@@ -764,7 +750,7 @@ fn lowerPtr(...@@ -764,7 +750,7 @@ fn lowerPtr(
764 },750 },
765 else => unreachable,751 else => unreachable,
766 };752 };
767 return lowerPtr(bin_file, pt, src_loc, field.base, code, reloc_parent, offset + field_off);753 return lowerPtr(bin_file, pt, src_loc, field.base, w, reloc_parent, offset + field_off);
768 },754 },
769 .arr_elem, .comptime_field, .comptime_alloc => unreachable,755 .arr_elem, .comptime_field, .comptime_alloc => unreachable,
770 };756 };
...@@ -775,12 +761,11 @@ fn lowerUavRef(...@@ -775,12 +761,11 @@ fn lowerUavRef(
775 pt: Zcu.PerThread,761 pt: Zcu.PerThread,
776 src_loc: Zcu.LazySrcLoc,762 src_loc: Zcu.LazySrcLoc,
777 uav: InternPool.Key.Ptr.BaseAddr.Uav,763 uav: InternPool.Key.Ptr.BaseAddr.Uav,
778 code: *ArrayList(u8),764 w: *std.Io.Writer,
779 reloc_parent: link.File.RelocInfo.Parent,765 reloc_parent: link.File.RelocInfo.Parent,
780 offset: u64,766 offset: u64,
781) GenerateSymbolError!void {767) (GenerateSymbolError || std.Io.Writer.Error)!void {
782 const zcu = pt.zcu;768 const zcu = pt.zcu;
783 const gpa = zcu.gpa;
784 const ip = &zcu.intern_pool;769 const ip = &zcu.intern_pool;
785 const comp = lf.comp;770 const comp = lf.comp;
786 const target = &comp.root_mod.resolved_target.result;771 const target = &comp.root_mod.resolved_target.result;
...@@ -790,10 +775,9 @@ fn lowerUavRef(...@@ -790,10 +775,9 @@ fn lowerUavRef(
790 const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn";775 const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn";
791776
792 log.debug("lowerUavRef: ty = {f}", .{uav_ty.fmt(pt)});777 log.debug("lowerUavRef: ty = {f}", .{uav_ty.fmt(pt)});
793 try code.ensureUnusedCapacity(gpa, ptr_width_bytes);
794778
795 if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) {779 if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) {
796 code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes);780 try w.splatByteAll(0xaa, ptr_width_bytes);
797 return;781 return;
798 }782 }
799783
...@@ -804,29 +788,32 @@ fn lowerUavRef(...@@ -804,29 +788,32 @@ fn lowerUavRef(
804 dev.check(link.File.Tag.wasm.devFeature());788 dev.check(link.File.Tag.wasm.devFeature());
805 const wasm = lf.cast(.wasm).?;789 const wasm = lf.cast(.wasm).?;
806 assert(reloc_parent == .none);790 assert(reloc_parent == .none);
807 try wasm.addUavReloc(code.items.len, uav.val, uav.orig_ty, @intCast(offset));791 try wasm.addUavReloc(w.end, uav.val, uav.orig_ty, @intCast(offset));
808 code.appendNTimesAssumeCapacity(0, ptr_width_bytes);792 try w.splatByteAll(0, ptr_width_bytes);
809 return;793 return;
810 },794 },
811 else => {},795 else => {},
812 }796 }
813797
814 const uav_align = ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment;798 const uav_align = Type.fromInterned(uav.orig_ty).ptrAlignment(zcu);
815 switch (try lf.lowerUav(pt, uav_val, uav_align, src_loc)) {799 switch (try lf.lowerUav(pt, uav_val, uav_align, src_loc)) {
816 .sym_index => {},800 .sym_index => {},
817 .fail => |em| std.debug.panic("TODO rework lowerUav. internal error: {s}", .{em.msg}),801 .fail => |em| std.debug.panic("TODO rework lowerUav. internal error: {s}", .{em.msg}),
818 }802 }
819803
820 const vaddr = try lf.getUavVAddr(uav_val, .{804 const vaddr = lf.getUavVAddr(uav_val, .{
821 .parent = reloc_parent,805 .parent = reloc_parent,
822 .offset = code.items.len,806 .offset = w.end,
823 .addend = @intCast(offset),807 .addend = @intCast(offset),
824 });808 }) catch |err| switch (err) {
809 error.OutOfMemory => return error.OutOfMemory,
810 else => |e| std.debug.panic("TODO rework lowerUav. internal error: {t}", .{e}),
811 };
825 const endian = target.cpu.arch.endian();812 const endian = target.cpu.arch.endian();
826 switch (ptr_width_bytes) {813 switch (ptr_width_bytes) {
827 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian),814 2 => try w.writeInt(u16, @intCast(vaddr), endian),
828 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian),815 4 => try w.writeInt(u32, @intCast(vaddr), endian),
829 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian),816 8 => try w.writeInt(u64, vaddr, endian),
830 else => unreachable,817 else => unreachable,
831 }818 }
832}819}
...@@ -835,10 +822,10 @@ fn lowerNavRef(...@@ -835,10 +822,10 @@ fn lowerNavRef(
835 lf: *link.File,822 lf: *link.File,
836 pt: Zcu.PerThread,823 pt: Zcu.PerThread,
837 nav_index: InternPool.Nav.Index,824 nav_index: InternPool.Nav.Index,
838 code: *ArrayList(u8),825 w: *std.Io.Writer,
839 reloc_parent: link.File.RelocInfo.Parent,826 reloc_parent: link.File.RelocInfo.Parent,
840 offset: u64,827 offset: u64,
841) GenerateSymbolError!void {828) (GenerateSymbolError || std.Io.Writer.Error)!void {
842 const zcu = pt.zcu;829 const zcu = pt.zcu;
843 const gpa = zcu.gpa;830 const gpa = zcu.gpa;
844 const ip = &zcu.intern_pool;831 const ip = &zcu.intern_pool;
...@@ -848,10 +835,8 @@ fn lowerNavRef(...@@ -848,10 +835,8 @@ fn lowerNavRef(
848 const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip));835 const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip));
849 const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";836 const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";
850837
851 try code.ensureUnusedCapacity(gpa, ptr_width_bytes);
852
853 if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) {838 if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) {
854 code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes);839 try w.splatByteAll(0xaa, ptr_width_bytes);
855 return;840 return;
856 }841 }
857842
...@@ -870,13 +855,13 @@ fn lowerNavRef(...@@ -870,13 +855,13 @@ fn lowerNavRef(
870 } else {855 } else {
871 try wasm.func_table_fixups.append(gpa, .{856 try wasm.func_table_fixups.append(gpa, .{
872 .table_index = @enumFromInt(gop.index),857 .table_index = @enumFromInt(gop.index),
873 .offset = @intCast(code.items.len),858 .offset = @intCast(w.end),
874 });859 });
875 }860 }
876 } else {861 } else {
877 if (is_obj) {862 if (is_obj) {
878 try wasm.out_relocs.append(gpa, .{863 try wasm.out_relocs.append(gpa, .{
879 .offset = @intCast(code.items.len),864 .offset = @intCast(w.end),
880 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },865 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },
881 .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64,866 .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64,
882 .addend = @intCast(offset),867 .addend = @intCast(offset),
...@@ -885,12 +870,12 @@ fn lowerNavRef(...@@ -885,12 +870,12 @@ fn lowerNavRef(
885 try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1);870 try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1);
886 wasm.nav_fixups.appendAssumeCapacity(.{871 wasm.nav_fixups.appendAssumeCapacity(.{
887 .navs_exe_index = try wasm.refNavExe(nav_index),872 .navs_exe_index = try wasm.refNavExe(nav_index),
888 .offset = @intCast(code.items.len),873 .offset = @intCast(w.end),
889 .addend = @intCast(offset),874 .addend = @intCast(offset),
890 });875 });
891 }876 }
892 }877 }
893 code.appendNTimesAssumeCapacity(0, ptr_width_bytes);878 try w.splatByteAll(0, ptr_width_bytes);
894 return;879 return;
895 },880 },
896 else => {},881 else => {},
...@@ -898,14 +883,14 @@ fn lowerNavRef(...@@ -898,14 +883,14 @@ fn lowerNavRef(
898883
899 const vaddr = lf.getNavVAddr(pt, nav_index, .{884 const vaddr = lf.getNavVAddr(pt, nav_index, .{
900 .parent = reloc_parent,885 .parent = reloc_parent,
901 .offset = code.items.len,886 .offset = w.end,
902 .addend = @intCast(offset),887 .addend = @intCast(offset),
903 }) catch @panic("TODO rework getNavVAddr");888 }) catch @panic("TODO rework getNavVAddr");
904 const endian = target.cpu.arch.endian();889 const endian = target.cpu.arch.endian();
905 switch (ptr_width_bytes) {890 switch (ptr_width_bytes) {
906 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian),891 2 => try w.writeInt(u16, @intCast(vaddr), endian),
907 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian),892 4 => try w.writeInt(u32, @intCast(vaddr), endian),
908 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian),893 8 => try w.writeInt(u64, vaddr, endian),
909 else => unreachable,894 else => unreachable,
910 }895 }
911}896}
...@@ -962,6 +947,16 @@ pub fn genNavRef(...@@ -962,6 +947,16 @@ pub fn genNavRef(
962 },947 },
963 .link_once => unreachable,948 .link_once => unreachable,
964 }949 }
950 } else if (lf.cast(.elf2)) |elf| {
951 return .{ .sym_index = @intFromEnum(elf.navSymbol(zcu, nav_index) catch |err| switch (err) {
952 error.OutOfMemory => return error.OutOfMemory,
953 else => |e| return .{ .fail = try ErrorMsg.create(
954 zcu.gpa,
955 src_loc,
956 "linker failed to create a nav: {t}",
957 .{e},
958 ) },
959 }) };
965 } else if (lf.cast(.macho)) |macho_file| {960 } else if (lf.cast(.macho)) |macho_file| {
966 const zo = macho_file.getZigObject().?;961 const zo = macho_file.getZigObject().?;
967 switch (linkage) {962 switch (linkage) {
src/codegen/aarch64/Mir.zig+27-28
...@@ -56,13 +56,13 @@ pub fn emit(...@@ -56,13 +56,13 @@ pub fn emit(
56 pt: Zcu.PerThread,56 pt: Zcu.PerThread,
57 src_loc: Zcu.LazySrcLoc,57 src_loc: Zcu.LazySrcLoc,
58 func_index: InternPool.Index,58 func_index: InternPool.Index,
59 code: *std.ArrayListUnmanaged(u8),59 atom_index: u32,
60 w: *std.Io.Writer,
60 debug_output: link.File.DebugInfoOutput,61 debug_output: link.File.DebugInfoOutput,
61) !void {62) !void {
62 _ = debug_output;63 _ = debug_output;
63 const zcu = pt.zcu;64 const zcu = pt.zcu;
64 const ip = &zcu.intern_pool;65 const ip = &zcu.intern_pool;
65 const gpa = zcu.gpa;
66 const func = zcu.funcInfo(func_index);66 const func = zcu.funcInfo(func_index);
67 const nav = ip.getNav(func.owner_nav);67 const nav = ip.getNav(func.owner_nav);
68 const mod = zcu.navFileScope(func.owner_nav).mod.?;68 const mod = zcu.navFileScope(func.owner_nav).mod.?;
...@@ -81,20 +81,19 @@ pub fn emit(...@@ -81,20 +81,19 @@ pub fn emit(
81 @as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)),81 @as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)),
82 Instruction.size,82 Instruction.size,
83 ) - 1);83 ) - 1);
84 try code.ensureUnusedCapacity(gpa, Instruction.size *84 try w.rebase(w.end, Instruction.size * (code_len + literals_align_gap + mir.literals.len));
85 (code_len + literals_align_gap + mir.literals.len));85 emitInstructionsForward(w, mir.prologue) catch unreachable;
86 emitInstructionsForward(code, mir.prologue);86 emitInstructionsBackward(w, mir.body) catch unreachable;
87 emitInstructionsBackward(code, mir.body);87 const body_end: u32 = @intCast(w.end);
88 const body_end: u32 = @intCast(code.items.len);88 emitInstructionsBackward(w, mir.epilogue) catch unreachable;
89 emitInstructionsBackward(code, mir.epilogue);89 w.splatByteAll(0, Instruction.size * literals_align_gap) catch unreachable;
90 code.appendNTimesAssumeCapacity(0, Instruction.size * literals_align_gap);90 w.writeAll(@ptrCast(mir.literals)) catch unreachable;
91 code.appendSliceAssumeCapacity(@ptrCast(mir.literals));
92 mir_log.debug("", .{});91 mir_log.debug("", .{});
9392
94 for (mir.nav_relocs) |nav_reloc| try emitReloc(93 for (mir.nav_relocs) |nav_reloc| try emitReloc(
95 lf,94 lf,
96 zcu,95 zcu,
97 func.owner_nav,96 atom_index,
98 switch (try @import("../../codegen.zig").genNavRef(97 switch (try @import("../../codegen.zig").genNavRef(
99 lf,98 lf,
100 pt,99 pt,
...@@ -112,7 +111,7 @@ pub fn emit(...@@ -112,7 +111,7 @@ pub fn emit(
112 for (mir.uav_relocs) |uav_reloc| try emitReloc(111 for (mir.uav_relocs) |uav_reloc| try emitReloc(
113 lf,112 lf,
114 zcu,113 zcu,
115 func.owner_nav,114 atom_index,
116 switch (try lf.lowerUav(115 switch (try lf.lowerUav(
117 pt,116 pt,
118 uav_reloc.uav.val,117 uav_reloc.uav.val,
...@@ -129,7 +128,7 @@ pub fn emit(...@@ -129,7 +128,7 @@ pub fn emit(
129 for (mir.lazy_relocs) |lazy_reloc| try emitReloc(128 for (mir.lazy_relocs) |lazy_reloc| try emitReloc(
130 lf,129 lf,
131 zcu,130 zcu,
132 func.owner_nav,131 atom_index,
133 if (lf.cast(.elf)) |ef|132 if (lf.cast(.elf)) |ef|
134 ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|133 ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|
135 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})134 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
...@@ -150,7 +149,7 @@ pub fn emit(...@@ -150,7 +149,7 @@ pub fn emit(
150 for (mir.global_relocs) |global_reloc| try emitReloc(149 for (mir.global_relocs) |global_reloc| try emitReloc(
151 lf,150 lf,
152 zcu,151 zcu,
153 func.owner_nav,152 atom_index,
154 if (lf.cast(.elf)) |ef|153 if (lf.cast(.elf)) |ef|
155 try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null)154 try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null)
156 else if (lf.cast(.macho)) |mf|155 else if (lf.cast(.macho)) |mf|
...@@ -168,30 +167,30 @@ pub fn emit(...@@ -168,30 +167,30 @@ pub fn emit(
168 var instruction = mir.body[literal_reloc.label];167 var instruction = mir.body[literal_reloc.label];
169 instruction.load_store.register_literal.group.imm19 += literal_reloc_offset;168 instruction.load_store.register_literal.group.imm19 += literal_reloc_offset;
170 instruction.write(169 instruction.write(
171 code.items[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size],170 w.buffered()[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size],
172 );171 );
173 }172 }
174}173}
175174
176fn emitInstructionsForward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void {175fn emitInstructionsForward(w: *std.Io.Writer, instructions: []const Instruction) !void {
177 for (instructions) |instruction| emitInstruction(code, instruction);176 for (instructions) |instruction| try emitInstruction(w, instruction);
178}177}
179fn emitInstructionsBackward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void {178fn emitInstructionsBackward(w: *std.Io.Writer, instructions: []const Instruction) !void {
180 var instruction_index = instructions.len;179 var instruction_index = instructions.len;
181 while (instruction_index > 0) {180 while (instruction_index > 0) {
182 instruction_index -= 1;181 instruction_index -= 1;
183 emitInstruction(code, instructions[instruction_index]);182 try emitInstruction(w, instructions[instruction_index]);
184 }183 }
185}184}
186fn emitInstruction(code: *std.ArrayListUnmanaged(u8), instruction: Instruction) void {185fn emitInstruction(w: *std.Io.Writer, instruction: Instruction) !void {
187 mir_log.debug(" {f}", .{instruction});186 mir_log.debug(" {f}", .{instruction});
188 instruction.write(code.addManyAsArrayAssumeCapacity(Instruction.size));187 instruction.write(try w.writableArray(Instruction.size));
189}188}
190189
191fn emitReloc(190fn emitReloc(
192 lf: *link.File,191 lf: *link.File,
193 zcu: *Zcu,192 zcu: *Zcu,
194 owner_nav: InternPool.Nav.Index,193 atom_index: u32,
195 sym_index: u32,194 sym_index: u32,
196 instruction: Instruction,195 instruction: Instruction,
197 offset: u32,196 offset: u32,
...@@ -202,7 +201,7 @@ fn emitReloc(...@@ -202,7 +201,7 @@ fn emitReloc(
202 else => unreachable,201 else => unreachable,
203 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {202 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
204 const zo = ef.zigObjectPtr().?;203 const zo = ef.zigObjectPtr().?;
205 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;204 const atom = zo.symbol(atom_index).atom(ef).?;
206 const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) {205 const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) {
207 else => unreachable,206 else => unreachable,
208 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {207 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
...@@ -221,7 +220,7 @@ fn emitReloc(...@@ -221,7 +220,7 @@ fn emitReloc(
221 }, zo);220 }, zo);
222 } else if (lf.cast(.macho)) |mf| {221 } else if (lf.cast(.macho)) |mf| {
223 const zo = mf.getZigObject().?;222 const zo = mf.getZigObject().?;
224 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;223 const atom = zo.symbols.items[atom_index].getAtom(mf).?;
225 switch (decoded.decode()) {224 switch (decoded.decode()) {
226 else => unreachable,225 else => unreachable,
227 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {226 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
...@@ -260,7 +259,7 @@ fn emitReloc(...@@ -260,7 +259,7 @@ fn emitReloc(
260 },259 },
261 .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {260 .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
262 const zo = ef.zigObjectPtr().?;261 const zo = ef.zigObjectPtr().?;
263 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;262 const atom = zo.symbol(atom_index).atom(ef).?;
264 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {263 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
265 .b => .JUMP26,264 .b => .JUMP26,
266 .bl => .CALL26,265 .bl => .CALL26,
...@@ -272,7 +271,7 @@ fn emitReloc(...@@ -272,7 +271,7 @@ fn emitReloc(
272 }, zo);271 }, zo);
273 } else if (lf.cast(.macho)) |mf| {272 } else if (lf.cast(.macho)) |mf| {
274 const zo = mf.getZigObject().?;273 const zo = mf.getZigObject().?;
275 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;274 const atom = zo.symbols.items[atom_index].getAtom(mf).?;
276 try atom.addReloc(mf, .{275 try atom.addReloc(mf, .{
277 .tag = .@"extern",276 .tag = .@"extern",
278 .offset = offset,277 .offset = offset,
...@@ -289,7 +288,7 @@ fn emitReloc(...@@ -289,7 +288,7 @@ fn emitReloc(
289 },288 },
290 .load_store => |decoded| if (lf.cast(.elf)) |ef| {289 .load_store => |decoded| if (lf.cast(.elf)) |ef| {
291 const zo = ef.zigObjectPtr().?;290 const zo = ef.zigObjectPtr().?;
292 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;291 const atom = zo.symbol(atom_index).atom(ef).?;
293 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {292 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {
294 .integer => |integer| switch (integer.decode()) {293 .integer => |integer| switch (integer.decode()) {
295 .unallocated, .prfm => unreachable,294 .unallocated, .prfm => unreachable,
...@@ -316,7 +315,7 @@ fn emitReloc(...@@ -316,7 +315,7 @@ fn emitReloc(
316 }, zo);315 }, zo);
317 } else if (lf.cast(.macho)) |mf| {316 } else if (lf.cast(.macho)) |mf| {
318 const zo = mf.getZigObject().?;317 const zo = mf.getZigObject().?;
319 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;318 const atom = zo.symbols.items[atom_index].getAtom(mf).?;
320 try atom.addReloc(mf, .{319 try atom.addReloc(mf, .{
321 .tag = .@"extern",320 .tag = .@"extern",
322 .offset = offset,321 .offset = offset,
src/dev.zig+4
...@@ -97,6 +97,7 @@ pub const Env = enum {...@@ -97,6 +97,7 @@ pub const Env = enum {
97 .lld_linker,97 .lld_linker,
98 .coff_linker,98 .coff_linker,
99 .elf_linker,99 .elf_linker,
100 .elf2_linker,
100 .macho_linker,101 .macho_linker,
101 .c_linker,102 .c_linker,
102 .wasm_linker,103 .wasm_linker,
...@@ -163,6 +164,7 @@ pub const Env = enum {...@@ -163,6 +164,7 @@ pub const Env = enum {
163 .incremental,164 .incremental,
164 .aarch64_backend,165 .aarch64_backend,
165 .elf_linker,166 .elf_linker,
167 .elf2_linker,
166 => true,168 => true,
167 else => Env.sema.supports(feature),169 else => Env.sema.supports(feature),
168 },170 },
...@@ -210,6 +212,7 @@ pub const Env = enum {...@@ -210,6 +212,7 @@ pub const Env = enum {
210 .legalize,212 .legalize,
211 .x86_64_backend,213 .x86_64_backend,
212 .elf_linker,214 .elf_linker,
215 .elf2_linker,
213 => true,216 => true,
214 else => Env.sema.supports(feature),217 else => Env.sema.supports(feature),
215 },218 },
...@@ -282,6 +285,7 @@ pub const Feature = enum {...@@ -282,6 +285,7 @@ pub const Feature = enum {
282 lld_linker,285 lld_linker,
283 coff_linker,286 coff_linker,
284 elf_linker,287 elf_linker,
288 elf2_linker,
285 macho_linker,289 macho_linker,
286 c_linker,290 c_linker,
287 wasm_linker,291 wasm_linker,
src/link.zig+80-11
...@@ -219,6 +219,7 @@ pub const Diags = struct {...@@ -219,6 +219,7 @@ pub const Diags = struct {
219 }219 }
220220
221 pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void {221 pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void {
222 @branchHint(.cold);
222 return addErrorSourceLocation(diags, .none, format, args);223 return addErrorSourceLocation(diags, .none, format, args);
223 }224 }
224225
...@@ -529,7 +530,7 @@ pub const File = struct {...@@ -529,7 +530,7 @@ pub const File = struct {
529 const lld: *Lld = try .createEmpty(arena, comp, emit, options);530 const lld: *Lld = try .createEmpty(arena, comp, emit, options);
530 return &lld.base;531 return &lld.base;
531 }532 }
532 switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {533 switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt, comp.config.use_new_linker)) {
533 .plan9 => return error.UnsupportedObjectFormat,534 .plan9 => return error.UnsupportedObjectFormat,
534 inline else => |tag| {535 inline else => |tag| {
535 dev.check(tag.devFeature());536 dev.check(tag.devFeature());
...@@ -552,7 +553,7 @@ pub const File = struct {...@@ -552,7 +553,7 @@ pub const File = struct {
552 const lld: *Lld = try .createEmpty(arena, comp, emit, options);553 const lld: *Lld = try .createEmpty(arena, comp, emit, options);
553 return &lld.base;554 return &lld.base;
554 }555 }
555 switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {556 switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt, comp.config.use_new_linker)) {
556 .plan9 => return error.UnsupportedObjectFormat,557 .plan9 => return error.UnsupportedObjectFormat,
557 inline else => |tag| {558 inline else => |tag| {
558 dev.check(tag.devFeature());559 dev.check(tag.devFeature());
...@@ -579,7 +580,8 @@ pub const File = struct {...@@ -579,7 +580,8 @@ pub const File = struct {
579 const emit = base.emit;580 const emit = base.emit;
580 if (base.child_pid) |pid| {581 if (base.child_pid) |pid| {
581 if (builtin.os.tag == .windows) {582 if (builtin.os.tag == .windows) {
582 base.cast(.coff).?.ptraceAttach(pid) catch |err| {583 const coff_file = base.cast(.coff).?;
584 coff_file.ptraceAttach(pid) catch |err| {
583 log.warn("attaching failed with error: {s}", .{@errorName(err)});585 log.warn("attaching failed with error: {s}", .{@errorName(err)});
584 };586 };
585 } else {587 } else {
...@@ -597,8 +599,11 @@ pub const File = struct {...@@ -597,8 +599,11 @@ pub const File = struct {
597 .linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {599 .linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
598 log.warn("ptrace failure: {s}", .{@errorName(err)});600 log.warn("ptrace failure: {s}", .{@errorName(err)});
599 },601 },
600 .macos => base.cast(.macho).?.ptraceAttach(pid) catch |err| {602 .macos => {
601 log.warn("attaching failed with error: {s}", .{@errorName(err)});603 const macho_file = base.cast(.macho).?;
604 macho_file.ptraceAttach(pid) catch |err| {
605 log.warn("attaching failed with error: {s}", .{@errorName(err)});
606 };
602 },607 },
603 .windows => unreachable,608 .windows => unreachable,
604 else => return error.HotSwapUnavailableOnHostOperatingSystem,609 else => return error.HotSwapUnavailableOnHostOperatingSystem,
...@@ -613,6 +618,20 @@ pub const File = struct {...@@ -613,6 +618,20 @@ pub const File = struct {
613 .mode = determineMode(output_mode, link_mode),618 .mode = determineMode(output_mode, link_mode),
614 });619 });
615 },620 },
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 }
634 },
616 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),635 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
617 .plan9 => unreachable,636 .plan9 => unreachable,
618 }637 }
...@@ -669,14 +688,30 @@ pub const File = struct {...@@ -669,14 +688,30 @@ pub const File = struct {
669688
670 if (base.child_pid) |pid| {689 if (base.child_pid) |pid| {
671 switch (builtin.os.tag) {690 switch (builtin.os.tag) {
672 .macos => base.cast(.macho).?.ptraceDetach(pid) catch |err| {691 .macos => {
673 log.warn("detaching failed with error: {s}", .{@errorName(err)});692 const macho_file = base.cast(.macho).?;
693 macho_file.ptraceDetach(pid) catch |err| {
694 log.warn("detaching failed with error: {s}", .{@errorName(err)});
695 };
696 },
697 .windows => {
698 const coff_file = base.cast(.coff).?;
699 coff_file.ptraceDetach(pid);
674 },700 },
675 .windows => base.cast(.coff).?.ptraceDetach(pid),
676 else => return error.HotSwapUnavailableOnHostOperatingSystem,701 else => return error.HotSwapUnavailableOnHostOperatingSystem,
677 }702 }
678 }703 }
679 },704 },
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 }
714 },
680 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),715 .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }),
681 .plan9 => unreachable,716 .plan9 => unreachable,
682 }717 }
...@@ -793,6 +828,7 @@ pub const File = struct {...@@ -793,6 +828,7 @@ pub const File = struct {
793 .spirv => {},828 .spirv => {},
794 .goff, .xcoff => {},829 .goff, .xcoff => {},
795 .plan9 => unreachable,830 .plan9 => unreachable,
831 .elf2 => {},
796 inline else => |tag| {832 inline else => |tag| {
797 dev.check(tag.devFeature());833 dev.check(tag.devFeature());
798 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id);834 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id);
...@@ -825,6 +861,26 @@ pub const File = struct {...@@ -825,6 +861,26 @@ pub const File = struct {
825 }861 }
826 }862 }
827863
864 pub fn idle(base: *File, tid: Zcu.PerThread.Id) !bool {
865 switch (base.tag) {
866 else => return false,
867 inline .elf2 => |tag| {
868 dev.check(tag.devFeature());
869 return @as(*tag.Type(), @fieldParentPtr("base", base)).idle(tid);
870 },
871 }
872 }
873
874 pub fn updateErrorData(base: *File, pt: Zcu.PerThread) !void {
875 switch (base.tag) {
876 else => {},
877 inline .elf2 => |tag| {
878 dev.check(tag.devFeature());
879 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateErrorData(pt);
880 },
881 }
882 }
883
828 pub const FlushError = error{884 pub const FlushError = error{
829 /// Indicates an error will be present in `Compilation.link_diags`.885 /// Indicates an error will be present in `Compilation.link_diags`.
830 LinkFailure,886 LinkFailure,
...@@ -1099,7 +1155,7 @@ pub const File = struct {...@@ -1099,7 +1155,7 @@ pub const File = struct {
1099 if (base.zcu_object_basename != null) return;1155 if (base.zcu_object_basename != null) return;
11001156
1101 switch (base.tag) {1157 switch (base.tag) {
1102 inline .wasm => |tag| {1158 inline .elf2, .wasm => |tag| {
1103 dev.check(tag.devFeature());1159 dev.check(tag.devFeature());
1104 return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node);1160 return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node);
1105 },1161 },
...@@ -1110,6 +1166,7 @@ pub const File = struct {...@@ -1110,6 +1166,7 @@ pub const File = struct {
1110 pub const Tag = enum {1166 pub const Tag = enum {
1111 coff,1167 coff,
1112 elf,1168 elf,
1169 elf2,
1113 macho,1170 macho,
1114 c,1171 c,
1115 wasm,1172 wasm,
...@@ -1123,6 +1180,7 @@ pub const File = struct {...@@ -1123,6 +1180,7 @@ pub const File = struct {
1123 return switch (tag) {1180 return switch (tag) {
1124 .coff => Coff,1181 .coff => Coff,
1125 .elf => Elf,1182 .elf => Elf,
1183 .elf2 => Elf2,
1126 .macho => MachO,1184 .macho => MachO,
1127 .c => C,1185 .c => C,
1128 .wasm => Wasm,1186 .wasm => Wasm,
...@@ -1134,10 +1192,10 @@ pub const File = struct {...@@ -1134,10 +1192,10 @@ pub const File = struct {
1134 };1192 };
1135 }1193 }
11361194
1137 fn fromObjectFormat(ofmt: std.Target.ObjectFormat) Tag {1195 fn fromObjectFormat(ofmt: std.Target.ObjectFormat, use_new_linker: bool) Tag {
1138 return switch (ofmt) {1196 return switch (ofmt) {
1139 .coff => .coff,1197 .coff => .coff,
1140 .elf => .elf,1198 .elf => if (use_new_linker) .elf2 else .elf,
1141 .macho => .macho,1199 .macho => .macho,
1142 .wasm => .wasm,1200 .wasm => .wasm,
1143 .plan9 => .plan9,1201 .plan9 => .plan9,
...@@ -1223,6 +1281,7 @@ pub const File = struct {...@@ -1223,6 +1281,7 @@ pub const File = struct {
1223 pub const C = @import("link/C.zig");1281 pub const C = @import("link/C.zig");
1224 pub const Coff = @import("link/Coff.zig");1282 pub const Coff = @import("link/Coff.zig");
1225 pub const Elf = @import("link/Elf.zig");1283 pub const Elf = @import("link/Elf.zig");
1284 pub const Elf2 = @import("link/Elf2.zig");
1226 pub const MachO = @import("link/MachO.zig");1285 pub const MachO = @import("link/MachO.zig");
1227 pub const SpirV = @import("link/SpirV.zig");1286 pub const SpirV = @import("link/SpirV.zig");
1228 pub const Wasm = @import("link/Wasm.zig");1287 pub const Wasm = @import("link/Wasm.zig");
...@@ -1548,6 +1607,9 @@ pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {...@@ -1548,6 +1607,9 @@ pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void {
1548 }1607 }
1549 }1608 }
1550}1609}
1610pub fn doIdleTask(comp: *Compilation, tid: usize) error{ OutOfMemory, LinkFailure }!bool {
1611 return if (comp.bin_file) |lf| lf.idle(@enumFromInt(tid)) else false;
1612}
1551/// After the main pipeline is done, but before flush, the compilation may need to link one final1613/// After the main pipeline is done, but before flush, the compilation may need to link one final
1552/// `Nav` into the binary: the `builtin.test_functions` value. Since the link thread isn't running1614/// `Nav` into the binary: the `builtin.test_functions` value. Since the link thread isn't running
1553/// by then, we expose this function which can be called directly.1615/// by then, we expose this function which can be called directly.
...@@ -1573,6 +1635,13 @@ pub fn linkTestFunctionsNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)...@@ -1573,6 +1635,13 @@ pub fn linkTestFunctionsNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
1573 };1635 };
1574 }1636 }
1575}1637}
1638pub fn updateErrorData(pt: Zcu.PerThread) void {
1639 const comp = pt.zcu.comp;
1640 if (comp.bin_file) |lf| lf.updateErrorData(pt) catch |err| switch (err) {
1641 error.OutOfMemory => comp.link_diags.setAllocFailure(),
1642 error.LinkFailure => {},
1643 };
1644}
15761645
1577/// Provided by the CLI, processed into `LinkInput` instances at the start of1646/// Provided by the CLI, processed into `LinkInput` instances at the start of
1578/// the compilation pipeline.1647/// the compilation pipeline.
src/link/Coff.zig+36-31
...@@ -953,7 +953,7 @@ fn writeOffsetTableEntry(coff: *Coff, index: usize) !void {...@@ -953,7 +953,7 @@ fn writeOffsetTableEntry(coff: *Coff, index: usize) !void {
953}953}
954954
955fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void {955fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void {
956 if (!coff.base.comp.incremental) return;956 if (!coff.base.comp.config.incremental) return;
957 // TODO: reverse-lookup might come in handy here957 // TODO: reverse-lookup might come in handy here
958 for (coff.relocs.values()) |*relocs| {958 for (coff.relocs.values()) |*relocs| {
959 for (relocs.items) |*reloc| {959 for (relocs.items) |*reloc| {
...@@ -964,7 +964,7 @@ fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void {...@@ -964,7 +964,7 @@ fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void {
964}964}
965965
966fn markRelocsDirtyByAddress(coff: *Coff, addr: u32) void {966fn markRelocsDirtyByAddress(coff: *Coff, addr: u32) void {
967 if (!coff.base.comp.incremental) return;967 if (!coff.base.comp.config.incremental) return;
968 const got_moved = blk: {968 const got_moved = blk: {
969 const sect_id = coff.got_section_index orelse break :blk false;969 const sect_id = coff.got_section_index orelse break :blk false;
970 break :blk coff.sections.items(.header)[sect_id].virtual_address >= addr;970 break :blk coff.sections.items(.header)[sect_id].virtual_address >= addr;
...@@ -1111,20 +1111,24 @@ pub fn updateFunc(...@@ -1111,20 +1111,24 @@ pub fn updateFunc(
11111111
1112 coff.navs.getPtr(func.owner_nav).?.section = coff.text_section_index.?;1112 coff.navs.getPtr(func.owner_nav).?.section = coff.text_section_index.?;
11131113
1114 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;1114 var aw: std.Io.Writer.Allocating = .init(gpa);
1115 defer code_buffer.deinit(gpa);1115 defer aw.deinit();
11161116
1117 try codegen.emitFunction(1117 codegen.emitFunction(
1118 &coff.base,1118 &coff.base,
1119 pt,1119 pt,
1120 zcu.navSrcLoc(nav_index),1120 zcu.navSrcLoc(nav_index),
1121 func_index,1121 func_index,
1122 coff.getAtom(atom_index).getSymbolIndex().?,
1122 mir,1123 mir,
1123 &code_buffer,1124 &aw.writer,
1124 .none,1125 .none,
1125 );1126 ) catch |err| switch (err) {
1127 error.WriteFailed => return error.OutOfMemory,
1128 else => |e| return e,
1129 };
11261130
1127 try coff.updateNavCode(pt, nav_index, code_buffer.items, .FUNCTION);1131 try coff.updateNavCode(pt, nav_index, aw.written(), .FUNCTION);
11281132
1129 // Exports will be updated by `Zcu.processExports` after the update.1133 // Exports will be updated by `Zcu.processExports` after the update.
1130}1134}
...@@ -1145,18 +1149,18 @@ fn lowerConst(...@@ -1145,18 +1149,18 @@ fn lowerConst(
1145) !LowerConstResult {1149) !LowerConstResult {
1146 const gpa = coff.base.comp.gpa;1150 const gpa = coff.base.comp.gpa;
11471151
1148 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;1152 var aw: std.Io.Writer.Allocating = .init(gpa);
1149 defer code_buffer.deinit(gpa);1153 defer aw.deinit();
11501154
1151 const atom_index = try coff.createAtom();1155 const atom_index = try coff.createAtom();
1152 const sym = coff.getAtom(atom_index).getSymbolPtr(coff);1156 const sym = coff.getAtom(atom_index).getSymbolPtr(coff);
1153 try coff.setSymbolName(sym, name);1157 try coff.setSymbolName(sym, name);
1154 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_id + 1));1158 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_id + 1));
11551159
1156 try codegen.generateSymbol(&coff.base, pt, src_loc, val, &code_buffer, .{1160 try codegen.generateSymbol(&coff.base, pt, src_loc, val, &aw.writer, .{
1157 .atom_index = coff.getAtom(atom_index).getSymbolIndex().?,1161 .atom_index = coff.getAtom(atom_index).getSymbolIndex().?,
1158 });1162 });
1159 const code = code_buffer.items;1163 const code = aw.written();
11601164
1161 const atom = coff.getAtomPtr(atom_index);1165 const atom = coff.getAtomPtr(atom_index);
1162 atom.size = @intCast(code.len);1166 atom.size = @intCast(code.len);
...@@ -1170,7 +1174,7 @@ fn lowerConst(...@@ -1170,7 +1174,7 @@ fn lowerConst(
1170 log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(coff).value });1174 log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(coff).value });
1171 log.debug(" (required alignment 0x{x})", .{required_alignment});1175 log.debug(" (required alignment 0x{x})", .{required_alignment});
11721176
1173 try coff.writeAtom(atom_index, code, coff.base.comp.incremental);1177 try coff.writeAtom(atom_index, code, coff.base.comp.config.incremental);
11741178
1175 return .{ .ok = atom_index };1179 return .{ .ok = atom_index };
1176}1180}
...@@ -1214,19 +1218,22 @@ pub fn updateNav(...@@ -1214,19 +1218,22 @@ pub fn updateNav(
12141218
1215 coff.navs.getPtr(nav_index).?.section = coff.getNavOutputSection(nav_index);1219 coff.navs.getPtr(nav_index).?.section = coff.getNavOutputSection(nav_index);
12161220
1217 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;1221 var aw: std.Io.Writer.Allocating = .init(gpa);
1218 defer code_buffer.deinit(gpa);1222 defer aw.deinit();
12191223
1220 try codegen.generateSymbol(1224 codegen.generateSymbol(
1221 &coff.base,1225 &coff.base,
1222 pt,1226 pt,
1223 zcu.navSrcLoc(nav_index),1227 zcu.navSrcLoc(nav_index),
1224 nav_init,1228 nav_init,
1225 &code_buffer,1229 &aw.writer,
1226 .{ .atom_index = atom.getSymbolIndex().? },1230 .{ .atom_index = atom.getSymbolIndex().? },
1227 );1231 ) catch |err| switch (err) {
1232 error.WriteFailed => return error.OutOfMemory,
1233 else => |e| return e,
1234 };
12281235
1229 try coff.updateNavCode(pt, nav_index, code_buffer.items, .NULL);1236 try coff.updateNavCode(pt, nav_index, aw.written(), .NULL);
1230 }1237 }
12311238
1232 // Exports will be updated by `Zcu.processExports` after the update.1239 // Exports will be updated by `Zcu.processExports` after the update.
...@@ -1244,8 +1251,8 @@ fn updateLazySymbolAtom(...@@ -1244,8 +1251,8 @@ fn updateLazySymbolAtom(
1244 const gpa = comp.gpa;1251 const gpa = comp.gpa;
12451252
1246 var required_alignment: InternPool.Alignment = .none;1253 var required_alignment: InternPool.Alignment = .none;
1247 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;1254 var aw: std.Io.Writer.Allocating = .init(gpa);
1248 defer code_buffer.deinit(gpa);1255 defer aw.deinit();
12491256
1250 const name = try allocPrint(gpa, "__lazy_{s}_{f}", .{1257 const name = try allocPrint(gpa, "__lazy_{s}_{f}", .{
1251 @tagName(sym.kind),1258 @tagName(sym.kind),
...@@ -1262,11 +1269,11 @@ fn updateLazySymbolAtom(...@@ -1262,11 +1269,11 @@ fn updateLazySymbolAtom(
1262 src,1269 src,
1263 sym,1270 sym,
1264 &required_alignment,1271 &required_alignment,
1265 &code_buffer,1272 &aw.writer,
1266 .none,1273 .none,
1267 .{ .atom_index = local_sym_index },1274 .{ .atom_index = local_sym_index },
1268 );1275 );
1269 const code = code_buffer.items;1276 const code = aw.written();
12701277
1271 const atom = coff.getAtomPtr(atom_index);1278 const atom = coff.getAtomPtr(atom_index);
1272 const symbol = atom.getSymbolPtr(coff);1279 const symbol = atom.getSymbolPtr(coff);
...@@ -1285,7 +1292,7 @@ fn updateLazySymbolAtom(...@@ -1285,7 +1292,7 @@ fn updateLazySymbolAtom(
1285 symbol.value = vaddr;1292 symbol.value = vaddr;
12861293
1287 try coff.addGotEntry(.{ .sym_index = local_sym_index });1294 try coff.addGotEntry(.{ .sym_index = local_sym_index });
1288 try coff.writeAtom(atom_index, code, coff.base.comp.incremental);1295 try coff.writeAtom(atom_index, code, coff.base.comp.config.incremental);
1289}1296}
12901297
1291pub fn getOrCreateAtomForLazySymbol(1298pub fn getOrCreateAtomForLazySymbol(
...@@ -1437,7 +1444,7 @@ fn updateNavCode(...@@ -1437,7 +1444,7 @@ fn updateNavCode(
1437 };1444 };
1438 }1445 }
14391446
1440 coff.writeAtom(atom_index, code, coff.base.comp.incremental) catch |err| switch (err) {1447 coff.writeAtom(atom_index, code, coff.base.comp.config.incremental) catch |err| switch (err) {
1441 error.OutOfMemory => return error.OutOfMemory,1448 error.OutOfMemory => return error.OutOfMemory,
1442 else => |e| return coff.base.cgFail(nav_index, "failed to write atom: {s}", .{@errorName(e)}),1449 else => |e| return coff.base.cgFail(nav_index, "failed to write atom: {s}", .{@errorName(e)}),
1443 };1450 };
...@@ -1539,14 +1546,12 @@ pub fn updateExports(...@@ -1539,14 +1546,12 @@ pub fn updateExports(
1539 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(metadata.section + 1));1546 sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(metadata.section + 1));
1540 sym.type = atom.getSymbol(coff).type;1547 sym.type = atom.getSymbol(coff).type;
15411548
1542 switch (exp.opts.linkage) {1549 sym.storage_class = switch (exp.opts.linkage) {
1543 .strong => {1550 .internal => .EXTERNAL,
1544 sym.storage_class = .EXTERNAL;1551 .strong => .EXTERNAL,
1545 },
1546 .internal => @panic("TODO Internal"),
1547 .weak => @panic("TODO WeakExternal"),1552 .weak => @panic("TODO WeakExternal"),
1548 else => unreachable,1553 else => unreachable,
1549 }1554 };
15501555
1551 try coff.resolveGlobalSymbol(sym_loc);1556 try coff.resolveGlobalSymbol(sym_loc);
1552 }1557 }
src/link/Dwarf.zig+10-7
...@@ -2126,19 +2126,22 @@ pub const WipNav = struct {...@@ -2126,19 +2126,22 @@ pub const WipNav = struct {
2126 const size = if (ty.hasRuntimeBits(wip_nav.pt.zcu)) ty.abiSize(wip_nav.pt.zcu) else 0;2126 const size = if (ty.hasRuntimeBits(wip_nav.pt.zcu)) ty.abiSize(wip_nav.pt.zcu) else 0;
2127 try diw.writeUleb128(size);2127 try diw.writeUleb128(size);
2128 if (size == 0) return;2128 if (size == 0) return;
2129 var bytes = wip_nav.debug_info.toArrayList();2129 const old_end = wip_nav.debug_info.writer.end;
2130 defer wip_nav.debug_info = .fromArrayList(wip_nav.dwarf.gpa, &bytes);
2131 const old_len = bytes.items.len;
2132 try codegen.generateSymbol(2130 try codegen.generateSymbol(
2133 wip_nav.dwarf.bin_file,2131 wip_nav.dwarf.bin_file,
2134 wip_nav.pt,2132 wip_nav.pt,
2135 src_loc,2133 src_loc,
2136 val,2134 val,
2137 &bytes,2135 &wip_nav.debug_info.writer,
2138 .{ .debug_output = .{ .dwarf = wip_nav } },2136 .{ .debug_output = .{ .dwarf = wip_nav } },
2139 );2137 );
2140 if (old_len + size != bytes.items.len) {2138 if (old_end + size != wip_nav.debug_info.writer.end) {
2141 std.debug.print("{f} [{}]: {} != {}\n", .{ ty.fmt(wip_nav.pt), ty.toIntern(), size, bytes.items.len - old_len });2139 std.debug.print("{f} [{}]: {} != {}\n", .{
2140 ty.fmt(wip_nav.pt),
2141 ty.toIntern(),
2142 size,
2143 wip_nav.debug_info.writer.end - old_end,
2144 });
2142 unreachable;2145 unreachable;
2143 }2146 }
2144 }2147 }
...@@ -6429,7 +6432,7 @@ fn sleb128Bytes(value: anytype) u32 {...@@ -6429,7 +6432,7 @@ fn sleb128Bytes(value: anytype) u32 {
6429/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional6432/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
6430const force_incremental = false;6433const force_incremental = false;
6431inline fn incremental(dwarf: Dwarf) bool {6434inline fn incremental(dwarf: Dwarf) bool {
6432 return force_incremental or dwarf.bin_file.comp.incremental;6435 return force_incremental or dwarf.bin_file.comp.config.incremental;
6433}6436}
64346437
6435const Allocator = std.mem.Allocator;6438const Allocator = std.mem.Allocator;
src/link/Elf/LinkerDefined.zig+1-1
...@@ -47,7 +47,7 @@ fn newSymbolAssumeCapacity(self: *LinkerDefined, name_off: u32, elf_file: *Elf)...@@ -47,7 +47,7 @@ fn newSymbolAssumeCapacity(self: *LinkerDefined, name_off: u32, elf_file: *Elf)
47 const esym = self.symtab.addOneAssumeCapacity();47 const esym = self.symtab.addOneAssumeCapacity();
48 esym.* = .{48 esym.* = .{
49 .st_name = name_off,49 .st_name = name_off,
50 .st_info = elf.STB_WEAK << 4,50 .st_info = @as(u8, elf.STB_WEAK) << 4,
51 .st_other = @intFromEnum(elf.STV.HIDDEN),51 .st_other = @intFromEnum(elf.STV.HIDDEN),
52 .st_shndx = elf.SHN_ABS,52 .st_shndx = elf.SHN_ABS,
53 .st_value = 0,53 .st_value = 0,
src/link/Elf/SharedObject.zig+1-1
...@@ -105,7 +105,7 @@ pub fn parseHeader(...@@ -105,7 +105,7 @@ pub fn parseHeader(
105 if (amt != buf.len) return error.UnexpectedEndOfFile;105 if (amt != buf.len) return error.UnexpectedEndOfFile;
106 }106 }
107 if (!mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")) return error.BadMagic;107 if (!mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")) return error.BadMagic;
108 if (ehdr.e_ident[elf.EI_VERSION] != 1) return error.BadElfVersion;108 if (ehdr.e_ident[elf.EI.VERSION] != 1) return error.BadElfVersion;
109 if (ehdr.e_type != elf.ET.DYN) return error.NotSharedObject;109 if (ehdr.e_type != elf.ET.DYN) return error.NotSharedObject;
110110
111 if (target.toElfMachine() != ehdr.e_machine)111 if (target.toElfMachine() != ehdr.e_machine)
src/link/Elf/ZigObject.zig+42-30
...@@ -277,8 +277,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {...@@ -277,8 +277,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
277 pt,277 pt,
278 .{ .kind = .code, .ty = .anyerror_type },278 .{ .kind = .code, .ty = .anyerror_type },
279 metadata.text_symbol_index,279 metadata.text_symbol_index,
280 ) catch |err| return switch (err) {280 ) catch |err| switch (err) {
281 error.CodegenFail => error.LinkFailure,281 error.CodegenFail => return error.LinkFailure,
282 else => |e| return e,282 else => |e| return e,
283 };283 };
284 if (metadata.rodata_state != .unused) self.updateLazySymbol(284 if (metadata.rodata_state != .unused) self.updateLazySymbol(
...@@ -286,8 +286,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {...@@ -286,8 +286,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
286 pt,286 pt,
287 .{ .kind = .const_data, .ty = .anyerror_type },287 .{ .kind = .const_data, .ty = .anyerror_type },
288 metadata.rodata_symbol_index,288 metadata.rodata_symbol_index,
289 ) catch |err| return switch (err) {289 ) catch |err| switch (err) {
290 error.CodegenFail => error.LinkFailure,290 error.CodegenFail => return error.LinkFailure,
291 else => |e| return e,291 else => |e| return e,
292 };292 };
293 }293 }
...@@ -1533,22 +1533,26 @@ pub fn updateFunc(...@@ -1533,22 +1533,26 @@ pub fn updateFunc(
1533 const sym_index = try self.getOrCreateMetadataForNav(zcu, func.owner_nav);1533 const sym_index = try self.getOrCreateMetadataForNav(zcu, func.owner_nav);
1534 self.atom(self.symbol(sym_index).ref.index).?.freeRelocs(self);1534 self.atom(self.symbol(sym_index).ref.index).?.freeRelocs(self);
15351535
1536 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;1536 var aw: std.Io.Writer.Allocating = .init(gpa);
1537 defer code_buffer.deinit(gpa);1537 defer aw.deinit();
15381538
1539 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;1539 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;
1540 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();1540 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
15411541
1542 try codegen.emitFunction(1542 codegen.emitFunction(
1543 &elf_file.base,1543 &elf_file.base,
1544 pt,1544 pt,
1545 zcu.navSrcLoc(func.owner_nav),1545 zcu.navSrcLoc(func.owner_nav),
1546 func_index,1546 func_index,
1547 sym_index,
1547 mir,1548 mir,
1548 &code_buffer,1549 &aw.writer,
1549 if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,1550 if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,
1550 );1551 ) catch |err| switch (err) {
1551 const code = code_buffer.items;1552 error.WriteFailed => return error.OutOfMemory,
1553 else => |e| return e,
1554 };
1555 const code = aw.written();
15521556
1553 const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code);1557 const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code);
1554 log.debug("setting shdr({x},{s}) for {f}", .{1558 log.debug("setting shdr({x},{s}) for {f}", .{
...@@ -1663,21 +1667,24 @@ pub fn updateNav(...@@ -1663,21 +1667,24 @@ pub fn updateNav(
1663 const sym_index = try self.getOrCreateMetadataForNav(zcu, nav_index);1667 const sym_index = try self.getOrCreateMetadataForNav(zcu, nav_index);
1664 self.symbol(sym_index).atom(elf_file).?.freeRelocs(self);1668 self.symbol(sym_index).atom(elf_file).?.freeRelocs(self);
16651669
1666 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;1670 var aw: std.Io.Writer.Allocating = .init(zcu.gpa);
1667 defer code_buffer.deinit(zcu.gpa);1671 defer aw.deinit();
16681672
1669 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;1673 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;
1670 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();1674 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
16711675
1672 try codegen.generateSymbol(1676 codegen.generateSymbol(
1673 &elf_file.base,1677 &elf_file.base,
1674 pt,1678 pt,
1675 zcu.navSrcLoc(nav_index),1679 zcu.navSrcLoc(nav_index),
1676 Value.fromInterned(nav_init),1680 Value.fromInterned(nav_init),
1677 &code_buffer,1681 &aw.writer,
1678 .{ .atom_index = sym_index },1682 .{ .atom_index = sym_index },
1679 );1683 ) catch |err| switch (err) {
1680 const code = code_buffer.items;1684 error.WriteFailed => return error.OutOfMemory,
1685 else => |e| return e,
1686 };
1687 const code = aw.written();
16811688
1682 const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code);1689 const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code);
1683 log.debug("setting shdr({x},{s}) for {f}", .{1690 log.debug("setting shdr({x},{s}) for {f}", .{
...@@ -1722,8 +1729,8 @@ fn updateLazySymbol(...@@ -1722,8 +1729,8 @@ fn updateLazySymbol(
1722 const gpa = zcu.gpa;1729 const gpa = zcu.gpa;
17231730
1724 var required_alignment: InternPool.Alignment = .none;1731 var required_alignment: InternPool.Alignment = .none;
1725 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;1732 var aw: std.Io.Writer.Allocating = .init(gpa);
1726 defer code_buffer.deinit(gpa);1733 defer aw.deinit();
17271734
1728 const name_str_index = blk: {1735 const name_str_index = blk: {
1729 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{1736 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{
...@@ -1734,18 +1741,20 @@ fn updateLazySymbol(...@@ -1734,18 +1741,20 @@ fn updateLazySymbol(
1734 break :blk try self.strtab.insert(gpa, name);1741 break :blk try self.strtab.insert(gpa, name);
1735 };1742 };
17361743
1737 const src = Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded;1744 codegen.generateLazySymbol(
1738 try codegen.generateLazySymbol(
1739 &elf_file.base,1745 &elf_file.base,
1740 pt,1746 pt,
1741 src,1747 Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse .unneeded,
1742 sym,1748 sym,
1743 &required_alignment,1749 &required_alignment,
1744 &code_buffer,1750 &aw.writer,
1745 .none,1751 .none,
1746 .{ .atom_index = symbol_index },1752 .{ .atom_index = symbol_index },
1747 );1753 ) catch |err| switch (err) {
1748 const code = code_buffer.items;1754 error.WriteFailed => return error.OutOfMemory,
1755 else => |e| return e,
1756 };
1757 const code = aw.written();
17491758
1750 const output_section_index = switch (sym.kind) {1759 const output_section_index = switch (sym.kind) {
1751 .code => if (self.text_index) |sym_index|1760 .code => if (self.text_index) |sym_index|
...@@ -1807,21 +1816,24 @@ fn lowerConst(...@@ -1807,21 +1816,24 @@ fn lowerConst(
1807) !codegen.SymbolResult {1816) !codegen.SymbolResult {
1808 const gpa = pt.zcu.gpa;1817 const gpa = pt.zcu.gpa;
18091818
1810 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;1819 var aw: std.Io.Writer.Allocating = .init(gpa);
1811 defer code_buffer.deinit(gpa);1820 defer aw.deinit();
18121821
1813 const name_off = try self.addString(gpa, name);1822 const name_off = try self.addString(gpa, name);
1814 const sym_index = try self.newSymbolWithAtom(gpa, name_off);1823 const sym_index = try self.newSymbolWithAtom(gpa, name_off);
18151824
1816 try codegen.generateSymbol(1825 codegen.generateSymbol(
1817 &elf_file.base,1826 &elf_file.base,
1818 pt,1827 pt,
1819 src_loc,1828 src_loc,
1820 val,1829 val,
1821 &code_buffer,1830 &aw.writer,
1822 .{ .atom_index = sym_index },1831 .{ .atom_index = sym_index },
1823 );1832 ) catch |err| switch (err) {
1824 const code = code_buffer.items;1833 error.WriteFailed => return error.OutOfMemory,
1834 else => |e| return e,
1835 };
1836 const code = aw.written();
18251837
1826 const local_sym = self.symbol(sym_index);1838 const local_sym = self.symbol(sym_index);
1827 const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index];1839 const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index];
src/link/Elf2.zig created+2036
...@@ -0,0 +1,2036 @@
1base: link.File,
2mf: MappedFile,
3nodes: std.MultiArrayList(Node),
4symtab: std.ArrayList(Symbol),
5shstrtab: StringTable,
6strtab: StringTable,
7globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index),
8navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index),
9uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
10lazy: std.EnumArray(link.File.LazySymbol.Kind, struct {
11 map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index),
12 pending_index: u32,
13}),
14pending_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct {
15 alignment: InternPool.Alignment,
16 src_loc: Zcu.LazySrcLoc,
17}),
18relocs: std.ArrayList(Reloc),
19/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly.
20entry_hack: Symbol.Index,
21
22pub const Node = union(enum) {
23 file,
24 ehdr,
25 shdr,
26 segment: u32,
27 section: Symbol.Index,
28 nav: InternPool.Nav.Index,
29 uav: InternPool.Index,
30 lazy_code: InternPool.Index,
31 lazy_const_data: InternPool.Index,
32
33 pub const Tag = @typeInfo(Node).@"union".tag_type.?;
34
35 const known_count = @typeInfo(@TypeOf(known)).@"struct".fields.len;
36 const known = known: {
37 const Known = enum {
38 file,
39 seg_rodata,
40 ehdr,
41 phdr,
42 shdr,
43 seg_text,
44 seg_data,
45 };
46 var mut_known: std.enums.EnumFieldStruct(
47 Known,
48 MappedFile.Node.Index,
49 null,
50 ) = undefined;
51 for (@typeInfo(Known).@"enum".fields) |field|
52 @field(mut_known, field.name) = @enumFromInt(field.value);
53 break :known mut_known;
54 };
55
56 comptime {
57 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8);
58 }
59};
60
61pub const StringTable = struct {
62 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
63 size: u32,
64
65 const Context = struct {
66 slice: []const u8,
67
68 pub fn eql(_: Context, lhs_key: u32, rhs_key: u32) bool {
69 return lhs_key == rhs_key;
70 }
71
72 pub fn hash(ctx: Context, key: u32) u64 {
73 return std.hash_map.hashString(std.mem.sliceTo(ctx.slice[key..], 0));
74 }
75 };
76
77 const Adapter = struct {
78 slice: []const u8,
79
80 pub fn eql(adapter: Adapter, lhs_key: []const u8, rhs_key: u32) bool {
81 return std.mem.startsWith(u8, adapter.slice[rhs_key..], lhs_key) and
82 adapter.slice[rhs_key + lhs_key.len] == 0;
83 }
84
85 pub fn hash(_: Adapter, key: []const u8) u64 {
86 assert(std.mem.indexOfScalar(u8, key, 0) == null);
87 return std.hash_map.hashString(key);
88 }
89 };
90
91 pub fn get(
92 st: *StringTable,
93 gpa: std.mem.Allocator,
94 mf: *MappedFile,
95 ni: MappedFile.Node.Index,
96 key: []const u8,
97 ) !u32 {
98 const slice_const = ni.sliceConst(mf);
99 const gop = try st.map.getOrPutContextAdapted(
100 gpa,
101 key,
102 StringTable.Adapter{ .slice = slice_const },
103 .{ .slice = slice_const },
104 );
105 if (gop.found_existing) return gop.key_ptr.*;
106 const old_size = st.size;
107 const new_size: u32 = @intCast(old_size + key.len + 1);
108 st.size = new_size;
109 try ni.resize(mf, gpa, new_size);
110 const slice = ni.slice(mf)[old_size..];
111 @memcpy(slice[0..key.len], key);
112 slice[key.len] = 0;
113 gop.key_ptr.* = old_size;
114 return old_size;
115 }
116};
117
118pub const Symbol = struct {
119 ni: MappedFile.Node.Index,
120 /// Relocations contained within this symbol
121 loc_relocs: Reloc.Index,
122 /// Relocations targeting this symbol
123 target_relocs: Reloc.Index,
124 unused: u32 = 0,
125
126 pub const Index = enum(u32) {
127 null,
128 symtab,
129 shstrtab,
130 strtab,
131 rodata,
132 text,
133 data,
134 tdata,
135 _,
136
137 pub fn get(si: Symbol.Index, elf: *Elf) *Symbol {
138 return &elf.symtab.items[@intFromEnum(si)];
139 }
140
141 pub fn node(si: Symbol.Index, elf: *Elf) MappedFile.Node.Index {
142 const ni = si.get(elf).ni;
143 assert(ni != .none);
144 return ni;
145 }
146
147 pub const InitOptions = struct {
148 name: []const u8 = "",
149 size: std.elf.Word = 0,
150 type: std.elf.STT,
151 bind: std.elf.STB = .LOCAL,
152 visibility: std.elf.STV = .DEFAULT,
153 shndx: std.elf.Section = std.elf.SHN_UNDEF,
154 };
155 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
156 const name_entry = try elf.string(.strtab, opts.name);
157 try Symbol.Index.symtab.node(elf).resize(
158 &elf.mf,
159 elf.base.comp.gpa,
160 @as(usize, switch (elf.identClass()) {
161 .NONE, _ => unreachable,
162 .@"32" => @sizeOf(std.elf.Elf32.Sym),
163 .@"64" => @sizeOf(std.elf.Elf64.Sym),
164 }) * elf.symtab.items.len,
165 );
166 switch (elf.symPtr(si)) {
167 inline else => |sym| sym.* = .{
168 .name = name_entry,
169 .value = 0,
170 .size = opts.size,
171 .info = .{
172 .type = opts.type,
173 .bind = opts.bind,
174 },
175 .other = .{
176 .visibility = opts.visibility,
177 },
178 .shndx = opts.shndx,
179 },
180 }
181 }
182
183 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {
184 for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| {
185 if (reloc.loc != si) break;
186 reloc.apply(elf);
187 }
188 }
189
190 pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void {
191 var ri = si.get(elf).target_relocs;
192 while (ri != .none) {
193 const reloc = ri.get(elf);
194 assert(reloc.target == si);
195 reloc.apply(elf);
196 ri = reloc.next;
197 }
198 }
199
200 pub fn deleteLocationRelocs(si: Symbol.Index, elf: *Elf) void {
201 const sym = si.get(elf);
202 for (elf.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| {
203 if (reloc.loc != si) break;
204 reloc.delete(elf);
205 }
206 sym.loc_relocs = .none;
207 }
208 };
209
210 comptime {
211 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16);
212 }
213};
214
215pub const Reloc = extern struct {
216 type: Reloc.Type,
217 prev: Reloc.Index,
218 next: Reloc.Index,
219 loc: Symbol.Index,
220 target: Symbol.Index,
221 unused: u32,
222 offset: u64,
223 addend: i64,
224
225 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,
230 };
231
232 pub const Index = enum(u32) {
233 none = std.math.maxInt(u32),
234 _,
235
236 pub fn get(si: Reloc.Index, elf: *Elf) *Reloc {
237 return &elf.relocs.items[@intFromEnum(si)];
238 }
239 };
240
241 pub fn apply(reloc: *const Reloc, elf: *Elf) void {
242 const target_endian = elf.endian();
243 switch (reloc.loc.get(elf).ni) {
244 .none => return,
245 else => |ni| if (ni.hasMoved(&elf.mf)) return,
246 }
247 switch (reloc.target.get(elf).ni) {
248 .none => return,
249 else => |ni| if (ni.hasMoved(&elf.mf)) return,
250 }
251 switch (elf.shdrSlice()) {
252 inline else => |shdr, class| {
253 const sym = @field(elf.symSlice(), @tagName(class));
254 const loc_sym = &sym[@intFromEnum(reloc.loc)];
255 const loc_shndx =
256 std.mem.toNative(@TypeOf(loc_sym.shndx), loc_sym.shndx, target_endian);
257 assert(loc_shndx != std.elf.SHN_UNDEF);
258 const loc_sh = &shdr[loc_shndx];
259 const loc_value = std.mem.toNative(
260 @TypeOf(loc_sym.value),
261 loc_sym.value,
262 target_endian,
263 ) + reloc.offset;
264 const loc_sh_addr =
265 std.mem.toNative(@TypeOf(loc_sh.addr), loc_sh.addr, target_endian);
266 const loc_sh_offset =
267 std.mem.toNative(@TypeOf(loc_sh.offset), loc_sh.offset, target_endian);
268 const loc_file_offset: usize = @intCast(loc_value - loc_sh_addr + loc_sh_offset);
269 const target_sym = &sym[@intFromEnum(reloc.target)];
270 const target_value = std.mem.toNative(
271 @TypeOf(target_sym.value),
272 target_sym.value,
273 target_endian,
274 ) +% @as(u64, @bitCast(reloc.addend));
275 switch (elf.ehdrField(.machine)) {
276 else => |machine| @panic(@tagName(machine)),
277 .X86_64 => switch (reloc.type.x86_64) {
278 else => |kind| @panic(@tagName(kind)),
279 .@"64" => std.mem.writeInt(
280 u64,
281 elf.mf.contents[loc_file_offset..][0..8],
282 target_value,
283 target_endian,
284 ),
285 .PC32 => std.mem.writeInt(
286 i32,
287 elf.mf.contents[loc_file_offset..][0..4],
288 @intCast(@as(i64, @bitCast(target_value -% loc_value))),
289 target_endian,
290 ),
291 .@"32" => std.mem.writeInt(
292 u32,
293 elf.mf.contents[loc_file_offset..][0..4],
294 @intCast(target_value),
295 target_endian,
296 ),
297 .TPOFF32 => {
298 const phdr = @field(elf.phdrSlice(), @tagName(class));
299 const ph = &phdr[4];
300 assert(std.mem.toNative(
301 @TypeOf(ph.type),
302 ph.type,
303 target_endian,
304 ) == std.elf.PT_TLS);
305 std.mem.writeInt(
306 i32,
307 elf.mf.contents[loc_file_offset..][0..4],
308 @intCast(@as(i64, @bitCast(target_value -% std.mem.toNative(
309 @TypeOf(ph.memsz),
310 ph.memsz,
311 target_endian,
312 )))),
313 target_endian,
314 );
315 },
316 },
317 }
318 },
319 }
320 }
321
322 pub fn delete(reloc: *Reloc, elf: *Elf) void {
323 switch (reloc.prev) {
324 .none => {
325 const target = reloc.target.get(elf);
326 assert(target.target_relocs.get(elf) == reloc);
327 target.target_relocs = reloc.next;
328 },
329 else => |prev| prev.get(elf).next = reloc.next,
330 }
331 switch (reloc.next) {
332 .none => {},
333 else => |next| next.get(elf).prev = reloc.prev,
334 }
335 reloc.* = undefined;
336 }
337
338 comptime {
339 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40);
340 }
341};
342
343pub fn open(
344 arena: std.mem.Allocator,
345 comp: *Compilation,
346 path: std.Build.Cache.Path,
347 options: link.File.OpenOptions,
348) !*Elf {
349 return create(arena, comp, path, options);
350}
351pub fn createEmpty(
352 arena: std.mem.Allocator,
353 comp: *Compilation,
354 path: std.Build.Cache.Path,
355 options: link.File.OpenOptions,
356) !*Elf {
357 return create(arena, comp, path, options);
358}
359fn create(
360 arena: std.mem.Allocator,
361 comp: *Compilation,
362 path: std.Build.Cache.Path,
363 options: link.File.OpenOptions,
364) !*Elf {
365 _ = options;
366 const target = &comp.root_mod.resolved_target.result;
367 assert(target.ofmt == .elf);
368 const class: std.elf.CLASS = switch (target.ptrBitWidth()) {
369 0...32 => .@"32",
370 33...64 => .@"64",
371 else => return error.UnsupportedELFArchitecture,
372 };
373 const data: std.elf.DATA = switch (target.cpu.arch.endian()) {
374 .little => .@"2LSB",
375 .big => .@"2MSB",
376 };
377 const osabi: std.elf.OSABI = switch (target.os.tag) {
378 else => .NONE,
379 .freestanding, .other => .STANDALONE,
380 .netbsd => .NETBSD,
381 .solaris => .SOLARIS,
382 .aix => .AIX,
383 .freebsd => .FREEBSD,
384 .cuda => .CUDA,
385 .amdhsa => .AMDGPU_HSA,
386 .amdpal => .AMDGPU_PAL,
387 .mesa3d => .AMDGPU_MESA3D,
388 };
389 const @"type": std.elf.ET = switch (comp.config.output_mode) {
390 .Exe => if (comp.config.pie or target.os.tag == .haiku) .DYN else .EXEC,
391 .Lib => switch (comp.config.link_mode) {
392 .static => .REL,
393 .dynamic => .DYN,
394 },
395 .Obj => .REL,
396 };
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 };
428 const maybe_interp = switch (comp.config.output_mode) {
429 .Exe, .Lib => switch (comp.config.link_mode) {
430 .static => null,
431 .dynamic => target.dynamic_linker.get(),
432 },
433 .Obj => null,
434 };
435
436 const elf = try arena.create(Elf);
437 const file = try path.root_dir.handle.createFile(path.sub_path, .{
438 .read = true,
439 .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode),
440 });
441 errdefer file.close();
442 elf.* = .{
443 .base = .{
444 .tag = .elf2,
445
446 .comp = comp,
447 .emit = path,
448
449 .file = file,
450 .gc_sections = false,
451 .print_gc_sections = false,
452 .build_id = .none,
453 .allow_shlib_undefined = false,
454 .stack_size = 0,
455 },
456 .mf = try .init(file, comp.gpa),
457 .nodes = .empty,
458 .symtab = .empty,
459 .shstrtab = .{
460 .map = .empty,
461 .size = 1,
462 },
463 .strtab = .{
464 .map = .empty,
465 .size = 1,
466 },
467 .globals = .empty,
468 .navs = .empty,
469 .uavs = .empty,
470 .lazy = .initFill(.{
471 .map = .empty,
472 .pending_index = 0,
473 }),
474 .pending_uavs = .empty,
475 .relocs = .empty,
476 .entry_hack = .null,
477 };
478 errdefer elf.deinit();
479
480 switch (class) {
481 .NONE, _ => unreachable,
482 inline .@"32", .@"64" => |ct_class| try elf.initHeaders(
483 ct_class,
484 data,
485 osabi,
486 @"type",
487 machine,
488 maybe_interp,
489 ),
490 }
491
492 return elf;
493}
494
495pub fn deinit(elf: *Elf) void {
496 const gpa = elf.base.comp.gpa;
497 elf.mf.deinit(gpa);
498 elf.nodes.deinit(gpa);
499 elf.symtab.deinit(gpa);
500 elf.shstrtab.map.deinit(gpa);
501 elf.strtab.map.deinit(gpa);
502 elf.globals.deinit(gpa);
503 elf.navs.deinit(gpa);
504 elf.uavs.deinit(gpa);
505 for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa);
506 elf.pending_uavs.deinit(gpa);
507 elf.relocs.deinit(gpa);
508 elf.* = undefined;
509}
510
511fn initHeaders(
512 elf: *Elf,
513 comptime class: std.elf.CLASS,
514 data: std.elf.DATA,
515 osabi: std.elf.OSABI,
516 @"type": std.elf.ET,
517 machine: std.elf.EM,
518 maybe_interp: ?[]const u8,
519) !void {
520 const comp = elf.base.comp;
521 const gpa = comp.gpa;
522 const ElfN = switch (class) {
523 .NONE, _ => comptime unreachable,
524 .@"32" => std.elf.Elf32,
525 .@"64" => std.elf.Elf64,
526 };
527 const addr_align: std.mem.Alignment = comptime .fromByteUnits(@sizeOf(ElfN.Addr));
528 const target_endian: std.builtin.Endian = switch (data) {
529 .NONE, _ => unreachable,
530 .@"2LSB" => .little,
531 .@"2MSB" => .big,
532 };
533
534 var phnum: u32 = 0;
535 const phdr_phndx = phnum;
536 phnum += 1;
537 const interp_phndx = if (maybe_interp) |_| phndx: {
538 defer phnum += 1;
539 break :phndx phnum;
540 } else undefined;
541 const rodata_phndx = phnum;
542 phnum += 1;
543 const text_phndx = phnum;
544 phnum += 1;
545 const data_phndx = phnum;
546 phnum += 1;
547 const tls_phndx = if (comp.config.any_non_single_threaded) phndx: {
548 defer phnum += 1;
549 break :phndx phnum;
550 } else undefined;
551
552 try elf.nodes.ensureTotalCapacity(gpa, Node.known_count);
553 elf.nodes.appendAssumeCapacity(.file);
554
555 const seg_rodata_ni = Node.known.seg_rodata;
556 assert(seg_rodata_ni == try elf.mf.addOnlyChildNode(gpa, .root, .{
557 .alignment = elf.mf.flags.block_size,
558 .fixed = true,
559 .moved = true,
560 }));
561 elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
562
563 const ehdr_ni = Node.known.ehdr;
564 assert(ehdr_ni == try elf.mf.addOnlyChildNode(gpa, seg_rodata_ni, .{
565 .size = @sizeOf(ElfN.Ehdr),
566 .alignment = addr_align,
567 .fixed = true,
568 }));
569 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);
594
595 const phdr_ni = Node.known.phdr;
596 assert(phdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{
597 .size = @sizeOf(ElfN.Phdr) * phnum,
598 .alignment = addr_align,
599 .moved = true,
600 .resized = true,
601 }));
602 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });
603
604 const shdr_ni = Node.known.shdr;
605 assert(shdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{
606 .size = @sizeOf(ElfN.Shdr),
607 .alignment = addr_align,
608 }));
609 elf.nodes.appendAssumeCapacity(.shdr);
610
611 const seg_text_ni = Node.known.seg_text;
612 assert(seg_text_ni == try elf.mf.addLastChildNode(gpa, .root, .{
613 .alignment = elf.mf.flags.block_size,
614 .moved = true,
615 }));
616 elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });
617
618 const seg_data_ni = Node.known.seg_data;
619 assert(seg_data_ni == try elf.mf.addLastChildNode(gpa, .root, .{
620 .alignment = elf.mf.flags.block_size,
621 .moved = true,
622 }));
623 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });
624
625 assert(elf.nodes.len == Node.known_count);
626
627 {
628 const phdr: []ElfN.Phdr = @ptrCast(@alignCast(phdr_ni.slice(&elf.mf)));
629 const ph_phdr = &phdr[phdr_phndx];
630 ph_phdr.* = .{
631 .type = std.elf.PT_PHDR,
632 .offset = 0,
633 .vaddr = 0,
634 .paddr = 0,
635 .filesz = 0,
636 .memsz = 0,
637 .flags = .{ .R = true },
638 .@"align" = @intCast(phdr_ni.alignment(&elf.mf).toByteUnits()),
639 };
640 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);
641
642 if (maybe_interp) |_| {
643 const ph_interp = &phdr[interp_phndx];
644 ph_interp.* = .{
645 .type = std.elf.PT_INTERP,
646 .offset = 0,
647 .vaddr = 0,
648 .paddr = 0,
649 .filesz = 0,
650 .memsz = 0,
651 .flags = .{ .R = true },
652 .@"align" = 1,
653 };
654 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);
655 }
656
657 const ph_rodata = &phdr[rodata_phndx];
658 ph_rodata.* = .{
659 .type = std.elf.PT_NULL,
660 .offset = 0,
661 .vaddr = 0,
662 .paddr = 0,
663 .filesz = 0,
664 .memsz = 0,
665 .flags = .{ .R = true },
666 .@"align" = @intCast(seg_rodata_ni.alignment(&elf.mf).toByteUnits()),
667 };
668 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
669
670 const ph_text = &phdr[text_phndx];
671 ph_text.* = .{
672 .type = std.elf.PT_NULL,
673 .offset = 0,
674 .vaddr = 0,
675 .paddr = 0,
676 .filesz = 0,
677 .memsz = 0,
678 .flags = .{ .R = true, .X = true },
679 .@"align" = @intCast(seg_text_ni.alignment(&elf.mf).toByteUnits()),
680 };
681 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
682
683 const ph_data = &phdr[data_phndx];
684 ph_data.* = .{
685 .type = std.elf.PT_NULL,
686 .offset = 0,
687 .vaddr = 0,
688 .paddr = 0,
689 .filesz = 0,
690 .memsz = 0,
691 .flags = .{ .R = true, .W = true },
692 .@"align" = @intCast(seg_data_ni.alignment(&elf.mf).toByteUnits()),
693 };
694 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
695
696 if (comp.config.any_non_single_threaded) {
697 const ph_tls = &phdr[tls_phndx];
698 ph_tls.* = .{
699 .type = std.elf.PT_TLS,
700 .offset = 0,
701 .vaddr = 0,
702 .paddr = 0,
703 .filesz = 0,
704 .memsz = 0,
705 .flags = .{ .R = true },
706 .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),
707 };
708 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
709 }
710
711 const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(shdr_ni.slice(&elf.mf)));
712 sh_null.* = .{
713 .name = try elf.string(.shstrtab, ""),
714 .type = std.elf.SHT_NULL,
715 .flags = .{ .shf = .{} },
716 .addr = 0,
717 .offset = 0,
718 .size = 0,
719 .link = 0,
720 .info = if (phnum >= std.elf.PN_XNUM) phnum else 0,
721 .addralign = 0,
722 .entsize = 0,
723 };
724 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_null);
725 }
726
727 try elf.symtab.ensureTotalCapacity(gpa, 1);
728 elf.symtab.addOneAssumeCapacity().* = .{
729 .ni = .none,
730 .loc_relocs = .none,
731 .target_relocs = .none,
732 .unused = 0,
733 };
734 assert(try elf.addSection(seg_rodata_ni, .{
735 .type = std.elf.SHT_SYMTAB,
736 .addralign = addr_align,
737 .entsize = @sizeOf(ElfN.Sym),
738 }) == .symtab);
739 const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf)));
740 symtab.* = .{
741 .name = try elf.string(.strtab, ""),
742 .value = 0,
743 .size = 0,
744 .info = .{
745 .type = .NOTYPE,
746 .bind = .LOCAL,
747 },
748 .other = .{
749 .visibility = .DEFAULT,
750 },
751 .shndx = std.elf.SHN_UNDEF,
752 };
753 ehdr.shstrndx = ehdr.shnum;
754 assert(try elf.addSection(seg_rodata_ni, .{
755 .type = std.elf.SHT_STRTAB,
756 .addralign = elf.mf.flags.block_size,
757 .entsize = 1,
758 }) == .shstrtab);
759 assert(try elf.addSection(seg_rodata_ni, .{
760 .type = std.elf.SHT_STRTAB,
761 .addralign = elf.mf.flags.block_size,
762 .entsize = 1,
763 }) == .strtab);
764 try elf.renameSection(.symtab, ".symtab");
765 try elf.renameSection(.shstrtab, ".shstrtab");
766 try elf.renameSection(.strtab, ".strtab");
767 try elf.linkSections(.symtab, .strtab);
768 Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0;
769 Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0;
770
771 assert(try elf.addSection(seg_rodata_ni, .{
772 .name = ".rodata",
773 .flags = .{ .ALLOC = true },
774 .addralign = elf.mf.flags.block_size,
775 }) == .rodata);
776 assert(try elf.addSection(seg_text_ni, .{
777 .name = ".text",
778 .flags = .{ .ALLOC = true, .EXECINSTR = true },
779 .addralign = elf.mf.flags.block_size,
780 }) == .text);
781 assert(try elf.addSection(seg_data_ni, .{
782 .name = ".data",
783 .flags = .{ .WRITE = true, .ALLOC = true },
784 .addralign = elf.mf.flags.block_size,
785 }) == .data);
786 if (comp.config.any_non_single_threaded) {
787 try elf.nodes.ensureUnusedCapacity(gpa, 1);
788 const seg_tls_ni = try elf.mf.addLastChildNode(gpa, seg_data_ni, .{
789 .alignment = elf.mf.flags.block_size,
790 .moved = true,
791 });
792 elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });
793
794 assert(try elf.addSection(seg_tls_ni, .{
795 .name = ".tdata",
796 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
797 .addralign = elf.mf.flags.block_size,
798 }) == .tdata);
799 }
800 if (maybe_interp) |interp| {
801 try elf.nodes.ensureUnusedCapacity(gpa, 1);
802 const seg_interp_ni = try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{
803 .size = interp.len + 1,
804 .moved = true,
805 .resized = true,
806 });
807 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
808
809 const sec_interp_si = try elf.addSection(seg_interp_ni, .{
810 .name = ".interp",
811 .size = @intCast(interp.len + 1),
812 .flags = .{ .ALLOC = true },
813 });
814 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
815 @memcpy(sec_interp[0..interp.len], interp);
816 sec_interp[interp.len] = 0;
817 }
818}
819
820fn getNode(elf: *Elf, ni: MappedFile.Node.Index) Node {
821 return elf.nodes.get(@intFromEnum(ni));
822}
823
824pub const EhdrPtr = union(std.elf.CLASS) {
825 NONE: noreturn,
826 @"32": *std.elf.Elf32.Ehdr,
827 @"64": *std.elf.Elf64.Ehdr,
828};
829pub fn ehdrPtr(elf: *Elf) EhdrPtr {
830 const slice = Node.known.ehdr.slice(&elf.mf);
831 return switch (elf.identClass()) {
832 .NONE, _ => unreachable,
833 inline .@"32", .@"64" => |class| @unionInit(
834 EhdrPtr,
835 @tagName(class),
836 @ptrCast(@alignCast(slice)),
837 ),
838 };
839}
840pub fn ehdrField(
841 elf: *Elf,
842 comptime field: enum { type, machine },
843) @FieldType(std.elf.Elf32.Ehdr, @tagName(field)) {
844 const Field = @FieldType(std.elf.Elf32.Ehdr, @tagName(field));
845 comptime assert(@FieldType(std.elf.Elf64.Ehdr, @tagName(field)) == Field);
846 return @enumFromInt(std.mem.toNative(
847 @typeInfo(Field).@"enum".tag_type,
848 @intFromEnum(switch (elf.ehdrPtr()) {
849 inline else => |ehdr| @field(ehdr, @tagName(field)),
850 }),
851 elf.endian(),
852 ));
853}
854
855pub fn identClass(elf: *Elf) std.elf.CLASS {
856 return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]);
857}
858
859pub fn identData(elf: *Elf) std.elf.DATA {
860 return @enumFromInt(elf.mf.contents[std.elf.EI.DATA]);
861}
862fn endianForData(data: std.elf.DATA) std.builtin.Endian {
863 return switch (data) {
864 .NONE, _ => unreachable,
865 .@"2LSB" => .little,
866 .@"2MSB" => .big,
867 };
868}
869pub fn endian(elf: *Elf) std.builtin.Endian {
870 return endianForData(elf.identData());
871}
872
873fn baseAddrForType(@"type": std.elf.ET) u64 {
874 return switch (@"type") {
875 else => 0,
876 .EXEC => 0x1000000,
877 };
878}
879pub fn baseAddr(elf: *Elf) u64 {
880 return baseAddrForType(elf.ehdrField(.type));
881}
882
883pub const PhdrSlice = union(std.elf.CLASS) {
884 NONE: noreturn,
885 @"32": []std.elf.Elf32.Phdr,
886 @"64": []std.elf.Elf64.Phdr,
887};
888pub fn phdrSlice(elf: *Elf) PhdrSlice {
889 const slice = Node.known.phdr.slice(&elf.mf);
890 return switch (elf.identClass()) {
891 .NONE, _ => unreachable,
892 inline .@"32", .@"64" => |class| @unionInit(
893 PhdrSlice,
894 @tagName(class),
895 @ptrCast(@alignCast(slice)),
896 ),
897 };
898}
899
900pub const ShdrSlice = union(std.elf.CLASS) {
901 NONE: noreturn,
902 @"32": []std.elf.Elf32.Shdr,
903 @"64": []std.elf.Elf64.Shdr,
904};
905pub fn shdrSlice(elf: *Elf) ShdrSlice {
906 const slice = Node.known.shdr.slice(&elf.mf);
907 return switch (elf.identClass()) {
908 .NONE, _ => unreachable,
909 inline .@"32", .@"64" => |class| @unionInit(
910 ShdrSlice,
911 @tagName(class),
912 @ptrCast(@alignCast(slice)),
913 ),
914 };
915}
916
917pub const SymSlice = union(std.elf.CLASS) {
918 NONE: noreturn,
919 @"32": []std.elf.Elf32.Sym,
920 @"64": []std.elf.Elf64.Sym,
921};
922pub fn symSlice(elf: *Elf) SymSlice {
923 const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf);
924 return switch (elf.identClass()) {
925 .NONE, _ => unreachable,
926 inline .@"32", .@"64" => |class| @unionInit(
927 SymSlice,
928 @tagName(class),
929 @ptrCast(@alignCast(slice)),
930 ),
931 };
932}
933
934pub const SymPtr = union(std.elf.CLASS) {
935 NONE: noreturn,
936 @"32": *std.elf.Elf32.Sym,
937 @"64": *std.elf.Elf64.Sym,
938};
939pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
940 return switch (elf.symSlice()) {
941 inline else => |sym, class| @unionInit(SymPtr, @tagName(class), &sym[@intFromEnum(si)]),
942 };
943}
944
945fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index {
946 defer elf.symtab.addOneAssumeCapacity().* = .{
947 .ni = .none,
948 .loc_relocs = .none,
949 .target_relocs = .none,
950 .unused = 0,
951 };
952 return @enumFromInt(elf.symtab.items.len);
953}
954
955fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index {
956 const si = try elf.addSymbolAssumeCapacity();
957 try si.init(elf, opts);
958 return si;
959}
960
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 {
970 const gpa = elf.base.comp.gpa;
971 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(.{
974 .name = opts.name,
975 .type = opts.type,
976 .bind = opts.bind,
977 .visibility = opts.visibility,
978 });
979 return sym_gop.value_ptr.*;
980}
981
982fn navType(
983 ip: *const InternPool,
984 nav_status: @FieldType(InternPool.Nav, "status"),
985 any_non_single_threaded: bool,
986) std.elf.STT {
987 return switch (nav_status) {
988 .unresolved => unreachable,
989 .type_resolved => |tr| if (any_non_single_threaded and tr.is_threadlocal)
990 .TLS
991 else if (ip.isFunctionType(tr.type))
992 .FUNC
993 else
994 .OBJECT,
995 .fully_resolved => |fr| switch (ip.indexToKey(fr.val)) {
996 else => .OBJECT,
997 .variable => |variable| if (any_non_single_threaded and variable.is_threadlocal)
998 .TLS
999 else
1000 .OBJECT,
1001 .@"extern" => |@"extern"| if (any_non_single_threaded and @"extern".is_threadlocal)
1002 .TLS
1003 else if (ip.isFunctionType(@"extern".ty))
1004 .FUNC
1005 else
1006 .OBJECT,
1007 .func => .FUNC,
1008 },
1009 };
1010}
1011pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {
1012 const gpa = zcu.gpa;
1013 const ip = &zcu.intern_pool;
1014 const nav = ip.getNav(nav_index);
1015 if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{
1016 .name = @"extern".name.toSlice(ip),
1017 .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),
1018 .bind = switch (@"extern".linkage) {
1019 .internal => .LOCAL,
1020 .strong => .GLOBAL,
1021 .weak => .WEAK,
1022 .link_once => return error.LinkOnceUnsupported,
1023 },
1024 .visibility = switch (@"extern".visibility) {
1025 .default => .DEFAULT,
1026 .hidden => .HIDDEN,
1027 .protected => .PROTECTED,
1028 },
1029 });
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.*;
1039}
1040
1041pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index {
1042 const gpa = elf.base.comp.gpa;
1043 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.*;
1048}
1049
1050pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index {
1051 const gpa = elf.base.comp.gpa;
1052 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(.{
1056 .type = switch (lazy.kind) {
1057 .code => .FUNC,
1058 .const_data => .OBJECT,
1059 },
1060 });
1061 elf.base.comp.link_lazy_prog_node.increaseEstimatedTotalItems(1);
1062 }
1063 return sym_gop.value_ptr.*;
1064}
1065
1066pub fn getNavVAddr(
1067 elf: *Elf,
1068 pt: Zcu.PerThread,
1069 nav: InternPool.Nav.Index,
1070 reloc_info: link.File.RelocInfo,
1071) !u64 {
1072 return elf.getVAddr(reloc_info, try elf.navSymbol(pt.zcu, nav));
1073}
1074
1075pub fn getUavVAddr(
1076 elf: *Elf,
1077 uav: InternPool.Index,
1078 reloc_info: link.File.RelocInfo,
1079) !u64 {
1080 return elf.getVAddr(reloc_info, try elf.uavSymbol(uav));
1081}
1082
1083pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 {
1084 try elf.addReloc(
1085 @enumFromInt(reloc_info.parent.atom_index),
1086 reloc_info.offset,
1087 target_si,
1088 reloc_info.addend,
1089 switch (elf.ehdrField(.machine)) {
1090 else => unreachable,
1091 .X86_64 => .{ .x86_64 = switch (elf.identClass()) {
1092 .NONE, _ => unreachable,
1093 .@"32" => .@"32",
1094 .@"64" => .@"64",
1095 } },
1096 },
1097 );
1098 return 0;
1099}
1100
1101fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1102 name: []const u8 = "",
1103 type: std.elf.Word = std.elf.SHT_NULL,
1104 size: std.elf.Word = 0,
1105 flags: std.elf.SHF = .{},
1106 addralign: std.mem.Alignment = .@"1",
1107 entsize: std.elf.Word = 0,
1108}) !Symbol.Index {
1109 const gpa = elf.base.comp.gpa;
1110 const target_endian = elf.endian();
1111 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1112 try elf.symtab.ensureUnusedCapacity(gpa, 1);
1113
1114 const shstrtab_entry = try elf.string(.shstrtab, opts.name);
1115 const shndx, const shdr_size = shndx: switch (elf.ehdrPtr()) {
1116 inline else => |ehdr| {
1117 const shentsize = std.mem.toNative(@TypeOf(ehdr.shentsize), ehdr.shentsize, target_endian);
1118 const shndx = std.mem.toNative(@TypeOf(ehdr.shnum), ehdr.shnum, target_endian);
1119 const shnum = shndx + 1;
1120 ehdr.shnum = std.mem.nativeTo(@TypeOf(ehdr.shnum), shnum, target_endian);
1121 break :shndx .{ shndx, shentsize * shnum };
1122 },
1123 };
1124 try Node.known.shdr.resize(&elf.mf, gpa, shdr_size);
1125 const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{
1126 .alignment = opts.addralign,
1127 .size = opts.size,
1128 .moved = true,
1129 });
1130 const si = try elf.addSymbolAssumeCapacity();
1131 elf.nodes.appendAssumeCapacity(.{ .section = si });
1132 si.get(elf).ni = ni;
1133 try si.init(elf, .{
1134 .name = opts.name,
1135 .size = opts.size,
1136 .type = .SECTION,
1137 .shndx = shndx,
1138 });
1139 switch (elf.shdrSlice()) {
1140 inline else => |shdr| {
1141 const sh = &shdr[shndx];
1142 sh.* = .{
1143 .name = shstrtab_entry,
1144 .type = opts.type,
1145 .flags = .{ .shf = opts.flags },
1146 .addr = 0,
1147 .offset = 0,
1148 .size = opts.size,
1149 .link = 0,
1150 .info = 0,
1151 .addralign = @intCast(opts.addralign.toByteUnits()),
1152 .entsize = opts.entsize,
1153 };
1154 if (target_endian != native_endian) std.mem.byteSwapAllFields(@TypeOf(sh.*), sh);
1155 },
1156 }
1157 return si;
1158}
1159
1160fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
1161 const strtab_entry = try elf.string(.strtab, name);
1162 const shstrtab_entry = try elf.string(.shstrtab, name);
1163 const target_endian = elf.endian();
1164 switch (elf.shdrSlice()) {
1165 inline else => |shdr, class| {
1166 const sym = @field(elf.symPtr(si), @tagName(class));
1167 sym.name = std.mem.nativeTo(@TypeOf(sym.name), strtab_entry, target_endian);
1168 const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian);
1169 const sh = &shdr[shndx];
1170 sh.name = std.mem.nativeTo(@TypeOf(sh.name), shstrtab_entry, target_endian);
1171 },
1172 }
1173}
1174
1175fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
1176 const target_endian = elf.endian();
1177 switch (elf.shdrSlice()) {
1178 inline else => |shdr, class| {
1179 const sym = @field(elf.symPtr(si), @tagName(class));
1180 const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian);
1181 shdr[shndx].link = @field(elf.symPtr(link_si), @tagName(class)).shndx;
1182 },
1183 }
1184}
1185
1186fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
1187 const target_endian = elf.endian();
1188 const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[name: switch (elf.shdrSlice()) {
1189 inline else => |shndx, class| {
1190 const sym = @field(elf.symPtr(si), @tagName(class));
1191 const sh = &shndx[std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian)];
1192 break :name std.mem.toNative(@TypeOf(sh.name), sh.name, target_endian);
1193 },
1194 }..];
1195 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
1196}
1197
1198fn string(elf: *Elf, comptime section: enum { shstrtab, strtab }, key: []const u8) !u32 {
1199 if (key.len == 0) return 0;
1200 return @field(elf, @tagName(section)).get(
1201 elf.base.comp.gpa,
1202 &elf.mf,
1203 @field(Symbol.Index, @tagName(section)).node(elf),
1204 key,
1205 );
1206}
1207
1208pub fn addReloc(
1209 elf: *Elf,
1210 loc_si: Symbol.Index,
1211 offset: u64,
1212 target_si: Symbol.Index,
1213 addend: i64,
1214 @"type": Reloc.Type,
1215) !void {
1216 const gpa = elf.base.comp.gpa;
1217 const target = target_si.get(elf);
1218 const ri: link.File.Elf2.Reloc.Index = @enumFromInt(elf.relocs.items.len);
1219 (try elf.relocs.addOne(gpa)).* = .{
1220 .type = @"type",
1221 .prev = .none,
1222 .next = target.target_relocs,
1223 .loc = loc_si,
1224 .target = target_si,
1225 .unused = 0,
1226 .offset = offset,
1227 .addend = addend,
1228 };
1229 switch (target.target_relocs) {
1230 .none => {},
1231 else => |target_ri| target_ri.get(elf).prev = ri,
1232 }
1233 target.target_relocs = ri;
1234}
1235
1236pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) void {
1237 _ = elf;
1238 _ = prog_node;
1239}
1240
1241pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
1242 elf.updateNavInner(pt, nav_index) catch |err| switch (err) {
1243 error.OutOfMemory,
1244 error.Overflow,
1245 error.RelocationNotByteAligned,
1246 => |e| return e,
1247 else => |e| return elf.base.cgFail(nav_index, "linker failed to update variable: {t}", .{e}),
1248 };
1249}
1250fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
1251 const comp = elf.base.comp;
1252 const zcu = pt.zcu;
1253 const gpa = zcu.gpa;
1254 const ip = &zcu.intern_pool;
1255
1256 const nav = ip.getNav(nav_index);
1257 const nav_val = nav.status.fully_resolved.val;
1258 const nav_init, const is_threadlocal = switch (ip.indexToKey(nav_val)) {
1259 else => .{ nav_val, false },
1260 .variable => |variable| .{ variable.init, variable.is_threadlocal },
1261 .@"extern" => return,
1262 .func => .{ .none, false },
1263 };
1264 if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return;
1265
1266 const si = try elf.navSymbol(zcu, nav_index);
1267 const ni = ni: {
1268 const sym = si.get(elf);
1269 switch (sym.ni) {
1270 .none => {
1271 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1272 const sec_si: Symbol.Index =
1273 if (is_threadlocal and comp.config.any_non_single_threaded) .tdata else .data;
1274 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
1275 .alignment = pt.navAlignment(nav_index).toStdMem(),
1276 .moved = true,
1277 });
1278 elf.nodes.appendAssumeCapacity(.{ .nav = nav_index });
1279 sym.ni = ni;
1280 switch (elf.symPtr(si)) {
1281 inline else => |sym_ptr, class| sym_ptr.shndx =
1282 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
1283 }
1284 },
1285 else => si.deleteLocationRelocs(elf),
1286 }
1287 assert(sym.loc_relocs == .none);
1288 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1289 break :ni sym.ni;
1290 };
1291
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;
1308 };
1309
1310 const target_endian = elf.endian();
1311 switch (elf.symPtr(si)) {
1312 inline else => |sym| sym.size =
1313 std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian),
1314 }
1315 si.applyLocationRelocs(elf);
1316}
1317
1318pub fn lowerUav(
1319 elf: *Elf,
1320 pt: Zcu.PerThread,
1321 uav_val: InternPool.Index,
1322 uav_align: InternPool.Alignment,
1323 src_loc: Zcu.LazySrcLoc,
1324) !codegen.SymbolResult {
1325 const zcu = pt.zcu;
1326 const gpa = zcu.gpa;
1327
1328 try elf.pending_uavs.ensureUnusedCapacity(gpa, 1);
1329 const si = elf.uavSymbol(uav_val) catch |err| switch (err) {
1330 error.OutOfMemory => return error.OutOfMemory,
1331 else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
1332 gpa,
1333 src_loc,
1334 "linker failed to update constant: {s}",
1335 .{@errorName(e)},
1336 ) },
1337 };
1338 if (switch (si.get(elf).ni) {
1339 .none => true,
1340 else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt),
1341 }) {
1342 const gop = elf.pending_uavs.getOrPutAssumeCapacity(uav_val);
1343 if (gop.found_existing) {
1344 gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align);
1345 } else {
1346 gop.value_ptr.* = .{
1347 .alignment = uav_align,
1348 .src_loc = src_loc,
1349 };
1350 elf.base.comp.link_uav_prog_node.increaseEstimatedTotalItems(1);
1351 }
1352 }
1353 return .{ .sym_index = @intFromEnum(si) };
1354}
1355
1356pub fn updateFunc(
1357 elf: *Elf,
1358 pt: Zcu.PerThread,
1359 func_index: InternPool.Index,
1360 mir: *const codegen.AnyMir,
1361) !void {
1362 elf.updateFuncInner(pt, func_index, mir) catch |err| switch (err) {
1363 error.OutOfMemory,
1364 error.Overflow,
1365 error.RelocationNotByteAligned,
1366 error.CodegenFail,
1367 => |e| return e,
1368 else => |e| return elf.base.cgFail(
1369 pt.zcu.funcInfo(func_index).owner_nav,
1370 "linker failed to update function: {s}",
1371 .{@errorName(e)},
1372 ),
1373 };
1374}
1375fn updateFuncInner(
1376 elf: *Elf,
1377 pt: Zcu.PerThread,
1378 func_index: InternPool.Index,
1379 mir: *const codegen.AnyMir,
1380) !void {
1381 const zcu = pt.zcu;
1382 const gpa = zcu.gpa;
1383 const ip = &zcu.intern_pool;
1384 const func = zcu.funcInfo(func_index);
1385 const nav = ip.getNav(func.owner_nav);
1386
1387 const si = try elf.navSymbol(zcu, func.owner_nav);
1388 log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si });
1389 const ni = ni: {
1390 const sym = si.get(elf);
1391 switch (sym.ni) {
1392 .none => {
1393 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1394 const mod = zcu.navFileScope(func.owner_nav).mod.?;
1395 const target = &mod.resolved_target.result;
1396 const ni = try elf.mf.addLastChildNode(gpa, Symbol.Index.text.node(elf), .{
1397 .alignment = switch (nav.status.fully_resolved.alignment) {
1398 .none => switch (mod.optimize_mode) {
1399 .Debug,
1400 .ReleaseSafe,
1401 .ReleaseFast,
1402 => target_util.defaultFunctionAlignment(target),
1403 .ReleaseSmall => target_util.minFunctionAlignment(target),
1404 },
1405 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
1406 }.toStdMem(),
1407 .moved = true,
1408 });
1409 elf.nodes.appendAssumeCapacity(.{ .nav = func.owner_nav });
1410 sym.ni = ni;
1411 switch (elf.symPtr(si)) {
1412 inline else => |sym_ptr, class| sym_ptr.shndx =
1413 @field(elf.symPtr(.text), @tagName(class)).shndx,
1414 }
1415 },
1416 else => si.deleteLocationRelocs(elf),
1417 }
1418 assert(sym.loc_relocs == .none);
1419 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1420 break :ni sym.ni;
1421 };
1422
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;
1441 };
1442
1443 const target_endian = elf.endian();
1444 switch (elf.symPtr(si)) {
1445 inline else => |sym| sym.size =
1446 std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian),
1447 }
1448 si.applyLocationRelocs(elf);
1449}
1450
1451pub 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) {
1454 error.OutOfMemory => return error.OutOfMemory,
1455 error.CodegenFail => return error.LinkFailure,
1456 else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}),
1457 };
1458}
1459
1460pub fn flush(
1461 elf: *Elf,
1462 arena: std.mem.Allocator,
1463 tid: Zcu.PerThread.Id,
1464 prog_node: std.Progress.Node,
1465) !void {
1466 _ = arena;
1467 _ = prog_node;
1468 while (try elf.idle(tid)) {}
1469}
1470
1471pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool {
1472 const comp = elf.base.comp;
1473 task: {
1474 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 );
1481 defer sub_prog_node.end();
1482 break :task elf.flushUav(
1483 .{ .zcu = elf.base.comp.zcu.?, .tid = tid },
1484 pending_uav.key,
1485 pending_uav.value.alignment,
1486 pending_uav.value.src_loc,
1487 ) catch |err| switch (err) {
1488 error.OutOfMemory => return error.OutOfMemory,
1489 else => |e| return elf.base.comp.link_diags.fail(
1490 "linker failed to lower constant: {t}",
1491 .{e},
1492 ),
1493 };
1494 }
1495 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;
1501 const pt: Zcu.PerThread = .{ .zcu = elf.base.comp.zcu.?, .tid = tid };
1502 const kind = switch (lazy.key) {
1503 .code => "code",
1504 .const_data => "data",
1505 };
1506 var name: [std.Progress.Node.max_name_len]u8 = undefined;
1507 const sub_prog_node = comp.link_lazy_prog_node.start(
1508 std.fmt.bufPrint(&name, "lazy {s} for {f}", .{
1509 kind,
1510 Type.fromInterned(ty).fmt(pt),
1511 }) catch &name,
1512 0,
1513 );
1514 defer sub_prog_node.end();
1515 break :task elf.flushLazy(pt, .{
1516 .kind = lazy.key,
1517 .ty = ty,
1518 }, si) catch |err| switch (err) {
1519 error.OutOfMemory => return error.OutOfMemory,
1520 else => |e| return elf.base.comp.link_diags.fail(
1521 "linker failed to lower lazy {s}: {t}",
1522 .{ kind, e },
1523 ),
1524 };
1525 };
1526 while (elf.mf.updates.pop()) |ni| {
1527 const clean_moved = ni.cleanMoved(&elf.mf);
1528 const clean_resized = ni.cleanResized(&elf.mf);
1529 if (clean_moved or clean_resized) {
1530 const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni));
1531 defer sub_prog_node.end();
1532 if (clean_moved) try elf.flushMoved(ni);
1533 if (clean_resized) try elf.flushResized(ni);
1534 break :task;
1535 } else elf.mf.update_prog_node.completeOne();
1536 }
1537 }
1538 if (elf.pending_uavs.count() > 0) return true;
1539 for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true;
1540 if (elf.mf.updates.items.len > 0) return true;
1541 return false;
1542}
1543
1544fn idleProgNode(
1545 elf: *Elf,
1546 tid: Zcu.PerThread.Id,
1547 prog_node: std.Progress.Node,
1548 node: Node,
1549) std.Progress.Node {
1550 var name: [std.Progress.Node.max_name_len]u8 = undefined;
1551 return prog_node.start(name: switch (node) {
1552 else => |tag| @tagName(tag),
1553 .section => |si| elf.sectionName(si),
1554 .nav => |nav| {
1555 const ip = &elf.base.comp.zcu.?.intern_pool;
1556 break :name ip.getNav(nav).fqn.toSlice(ip);
1557 },
1558 .uav => |uav| std.fmt.bufPrint(&name, "{f}", .{
1559 Value.fromInterned(uav).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }),
1560 }) catch &name,
1561 }, 0);
1562}
1563
1564fn flushUav(
1565 elf: *Elf,
1566 pt: Zcu.PerThread,
1567 uav_val: InternPool.Index,
1568 uav_align: InternPool.Alignment,
1569 src_loc: Zcu.LazySrcLoc,
1570) !void {
1571 const zcu = pt.zcu;
1572 const gpa = zcu.gpa;
1573
1574 const si = try elf.uavSymbol(uav_val);
1575 const ni = ni: {
1576 const sym = si.get(elf);
1577 switch (sym.ni) {
1578 .none => {
1579 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1580 const ni = try elf.mf.addLastChildNode(gpa, Symbol.Index.data.node(elf), .{
1581 .alignment = uav_align.toStdMem(),
1582 .moved = true,
1583 });
1584 elf.nodes.appendAssumeCapacity(.{ .uav = uav_val });
1585 sym.ni = ni;
1586 switch (elf.symPtr(si)) {
1587 inline else => |sym_ptr, class| sym_ptr.shndx =
1588 @field(elf.symPtr(.data), @tagName(class)).shndx,
1589 }
1590 },
1591 else => {
1592 if (sym.ni.alignment(&elf.mf).order(uav_align.toStdMem()).compare(.gte)) return;
1593 si.deleteLocationRelocs(elf);
1594 },
1595 }
1596 assert(sym.loc_relocs == .none);
1597 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1598 break :ni sym.ni;
1599 };
1600
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;
1617 };
1618
1619 const target_endian = elf.endian();
1620 switch (elf.symPtr(si)) {
1621 inline else => |sym| sym.size =
1622 std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian),
1623 }
1624 si.applyLocationRelocs(elf);
1625}
1626
1627fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbol.Index) !void {
1628 const zcu = pt.zcu;
1629 const gpa = zcu.gpa;
1630
1631 const ni = ni: {
1632 const sym = si.get(elf);
1633 switch (sym.ni) {
1634 .none => {
1635 try elf.nodes.ensureUnusedCapacity(gpa, 1);
1636 const sec_si: Symbol.Index = switch (lazy.kind) {
1637 .code => .text,
1638 .const_data => .rodata,
1639 };
1640 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true });
1641 elf.nodes.appendAssumeCapacity(switch (lazy.kind) {
1642 .code => .{ .lazy_code = lazy.ty },
1643 .const_data => .{ .lazy_const_data = lazy.ty },
1644 });
1645 sym.ni = ni;
1646 switch (elf.symPtr(si)) {
1647 inline else => |sym_ptr, class| sym_ptr.shndx =
1648 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
1649 }
1650 },
1651 else => si.deleteLocationRelocs(elf),
1652 }
1653 assert(sym.loc_relocs == .none);
1654 sym.loc_relocs = @enumFromInt(elf.relocs.items.len);
1655 break :ni sym.ni;
1656 };
1657
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();
1677 switch (elf.symPtr(si)) {
1678 inline else => |sym| sym.size =
1679 std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian),
1680 }
1681 si.applyLocationRelocs(elf);
1682}
1683
1684fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
1685 const target_endian = elf.endian();
1686 const file_offset = ni.fileLocation(&elf.mf, false).offset;
1687 const node = elf.getNode(ni);
1688 switch (node) {
1689 else => |tag| @panic(@tagName(tag)),
1690 .ehdr => assert(file_offset == 0),
1691 .shdr => switch (elf.ehdrPtr()) {
1692 inline else => |ehdr| ehdr.shoff =
1693 std.mem.nativeTo(@TypeOf(ehdr.shoff), @intCast(file_offset), target_endian),
1694 },
1695 .segment => |phndx| switch (elf.phdrSlice()) {
1696 inline else => |phdr, class| {
1697 const ph = &phdr[phndx];
1698 switch (std.mem.toNative(@TypeOf(ph.type), ph.type, target_endian)) {
1699 else => unreachable,
1700 std.elf.PT_NULL, std.elf.PT_LOAD, std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {},
1701 std.elf.PT_PHDR => {
1702 const ehdr = @field(elf.ehdrPtr(), @tagName(class));
1703 ehdr.phoff =
1704 std.mem.nativeTo(@TypeOf(ehdr.phoff), @intCast(file_offset), target_endian);
1705 },
1706 std.elf.PT_TLS => {},
1707 }
1708 ph.offset = std.mem.nativeTo(@TypeOf(ph.offset), @intCast(file_offset), target_endian);
1709 ph.vaddr = std.mem.nativeTo(
1710 @TypeOf(ph.vaddr),
1711 @intCast(elf.baseAddr() + file_offset),
1712 target_endian,
1713 );
1714 ph.paddr = ph.vaddr;
1715 },
1716 },
1717 .section => |si| switch (elf.shdrSlice()) {
1718 inline else => |shdr, class| {
1719 const sym = @field(elf.symPtr(si), @tagName(class));
1720 const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian);
1721 const sh = &shdr[shndx];
1722 const flags: @TypeOf(sh.flags) = @bitCast(std.mem.toNative(
1723 @typeInfo(@TypeOf(sh.flags)).@"struct".backing_integer.?,
1724 @bitCast(sh.flags),
1725 target_endian,
1726 ));
1727 if (flags.shf.ALLOC) {
1728 sym.value = std.mem.nativeTo(
1729 @TypeOf(sym.value),
1730 @intCast(elf.baseAddr() + file_offset),
1731 target_endian,
1732 );
1733 sh.addr = sym.value;
1734 }
1735 sh.offset = std.mem.nativeTo(@TypeOf(sh.offset), @intCast(file_offset), target_endian);
1736 },
1737 },
1738 .nav, .uav, .lazy_code, .lazy_const_data => {
1739 const si = switch (node) {
1740 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 }.?;
1746 switch (elf.shdrSlice()) {
1747 inline else => |shdr, class| {
1748 const sym = @field(elf.symPtr(si), @tagName(class));
1749 const sh = &shdr[std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian)];
1750 const flags: @TypeOf(sh.flags) = @bitCast(std.mem.toNative(
1751 @typeInfo(@TypeOf(sh.flags)).@"struct".backing_integer.?,
1752 @bitCast(sh.flags),
1753 target_endian,
1754 ));
1755 const sh_addr = if (flags.shf.TLS)
1756 0
1757 else
1758 std.mem.toNative(@TypeOf(sh.addr), sh.addr, target_endian);
1759 const sh_offset = std.mem.toNative(@TypeOf(sh.offset), sh.offset, target_endian);
1760 sym.value = std.mem.nativeTo(
1761 @TypeOf(sym.value),
1762 @intCast(file_offset - sh_offset + sh_addr),
1763 target_endian,
1764 );
1765 if (si == elf.entry_hack) @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value;
1766 },
1767 }
1768 si.applyLocationRelocs(elf);
1769 si.applyTargetRelocs(elf);
1770 },
1771 }
1772 try ni.childrenMoved(elf.base.comp.gpa, &elf.mf);
1773}
1774
1775fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
1776 const target_endian = elf.endian();
1777 _, const size = ni.location(&elf.mf).resolve(&elf.mf);
1778 const node = elf.getNode(ni);
1779 switch (node) {
1780 else => |tag| @panic(@tagName(tag)),
1781 .file, .shdr => {},
1782 .segment => |phndx| switch (elf.phdrSlice()) {
1783 inline else => |phdr| {
1784 const ph = &phdr[phndx];
1785 ph.filesz = std.mem.nativeTo(@TypeOf(ph.filesz), @intCast(size), target_endian);
1786 ph.memsz = ph.filesz;
1787 switch (std.mem.toNative(@TypeOf(ph.type), ph.type, target_endian)) {
1788 else => unreachable,
1789 std.elf.PT_NULL => {
1790 if (size > 0) ph.type = std.mem.nativeTo(
1791 @TypeOf(ph.type),
1792 std.elf.PT_LOAD,
1793 target_endian,
1794 );
1795 },
1796 std.elf.PT_LOAD => {
1797 if (size == 0) ph.type = std.mem.nativeTo(
1798 @TypeOf(ph.type),
1799 std.elf.PT_NULL,
1800 target_endian,
1801 );
1802 },
1803 std.elf.PT_DYNAMIC, std.elf.PT_INTERP, std.elf.PT_PHDR => {},
1804 std.elf.PT_TLS => try ni.childrenMoved(elf.base.comp.gpa, &elf.mf),
1805 }
1806 },
1807 },
1808 .section => |si| switch (elf.shdrSlice()) {
1809 inline else => |shdr, class| {
1810 const sym = @field(elf.symPtr(si), @tagName(class));
1811 const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian);
1812 const sh = &shdr[shndx];
1813 switch (std.mem.toNative(@TypeOf(sh.type), sh.type, target_endian)) {
1814 else => unreachable,
1815 std.elf.SHT_NULL => {
1816 if (size > 0) sh.type = std.mem.nativeTo(
1817 @TypeOf(sh.type),
1818 std.elf.SHT_PROGBITS,
1819 target_endian,
1820 );
1821 },
1822 std.elf.SHT_PROGBITS => {
1823 if (size == 0) sh.type = std.mem.nativeTo(
1824 @TypeOf(sh.type),
1825 std.elf.SHT_NULL,
1826 target_endian,
1827 );
1828 },
1829 std.elf.SHT_SYMTAB => sh.info = std.mem.nativeTo(
1830 @TypeOf(sh.info),
1831 @intCast(@divExact(
1832 size,
1833 std.mem.toNative(@TypeOf(sh.entsize), sh.entsize, target_endian),
1834 )),
1835 target_endian,
1836 ),
1837 std.elf.SHT_STRTAB => {},
1838 }
1839 sh.size = std.mem.nativeTo(@TypeOf(sh.size), @intCast(size), target_endian);
1840 },
1841 },
1842 .nav, .uav, .lazy_code, .lazy_const_data => {},
1843 }
1844}
1845
1846pub fn updateExports(
1847 elf: *Elf,
1848 pt: Zcu.PerThread,
1849 exported: Zcu.Exported,
1850 export_indices: []const Zcu.Export.Index,
1851) !void {
1852 return elf.updateExportsInner(pt, exported, export_indices) catch |err| switch (err) {
1853 error.OutOfMemory => error.OutOfMemory,
1854 error.LinkFailure => error.AnalysisFail,
1855 else => |e| switch (elf.base.comp.link_diags.fail(
1856 "linker failed to update exports: {t}",
1857 .{e},
1858 )) {
1859 error.LinkFailure => return error.AnalysisFail,
1860 },
1861 };
1862}
1863fn updateExportsInner(
1864 elf: *Elf,
1865 pt: Zcu.PerThread,
1866 exported: Zcu.Exported,
1867 export_indices: []const Zcu.Export.Index,
1868) !void {
1869 const zcu = pt.zcu;
1870 const gpa = zcu.gpa;
1871 const ip = &zcu.intern_pool;
1872
1873 switch (exported) {
1874 .nav => |nav| log.debug("updateExports({f})", .{ip.getNav(nav).fqn.fmt(ip)}),
1875 .uav => |uav| log.debug("updateExports(@as({f}, {f}))", .{
1876 Type.fromInterned(ip.typeOf(uav)).fmt(pt),
1877 Value.fromInterned(uav).fmtValue(pt),
1878 }),
1879 }
1880 try elf.symtab.ensureUnusedCapacity(gpa, export_indices.len);
1881 const exported_si: Symbol.Index, const @"type": std.elf.STT = switch (exported) {
1882 .nav => |nav| .{
1883 try elf.navSymbol(zcu, nav),
1884 navType(ip, ip.getNav(nav).status, elf.base.comp.config.any_non_single_threaded),
1885 },
1886 .uav => |uav| .{ @enumFromInt(switch (try elf.lowerUav(
1887 pt,
1888 uav,
1889 Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu),
1890 export_indices[0].ptr(zcu).src,
1891 )) {
1892 .sym_index => |si| si,
1893 .fail => |em| {
1894 defer em.destroy(gpa);
1895 return elf.base.comp.link_diags.fail("{s}", .{em.msg});
1896 },
1897 }), .OBJECT },
1898 };
1899 while (try elf.idle(pt.tid)) {}
1900 const exported_ni = exported_si.node(elf);
1901 const value, const size, const shndx = switch (elf.symPtr(exported_si)) {
1902 inline else => |exported_sym| .{ exported_sym.value, exported_sym.size, exported_sym.shndx },
1903 };
1904 for (export_indices) |export_index| {
1905 const @"export" = export_index.ptr(zcu);
1906 const name = @"export".opts.name.toSlice(ip);
1907 const export_si = try elf.globalSymbol(.{
1908 .name = name,
1909 .type = @"type",
1910 .bind = switch (@"export".opts.linkage) {
1911 .internal => .LOCAL,
1912 .strong => .GLOBAL,
1913 .weak => .WEAK,
1914 .link_once => return error.LinkOnceUnsupported,
1915 },
1916 .visibility = switch (@"export".opts.visibility) {
1917 .default => .DEFAULT,
1918 .hidden => .HIDDEN,
1919 .protected => .PROTECTED,
1920 },
1921 });
1922 export_si.get(elf).ni = exported_ni;
1923 switch (elf.symPtr(export_si)) {
1924 inline else => |export_sym| {
1925 export_sym.value = @intCast(value);
1926 export_sym.size = @intCast(size);
1927 export_sym.shndx = shndx;
1928 },
1929 }
1930 export_si.applyTargetRelocs(elf);
1931 if (std.mem.eql(u8, name, "_start")) {
1932 elf.entry_hack = exported_si;
1933 switch (elf.ehdrPtr()) {
1934 inline else => |ehdr| ehdr.entry = @intCast(value),
1935 }
1936 }
1937 }
1938}
1939
1940pub fn deleteExport(elf: *Elf, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void {
1941 _ = elf;
1942 _ = exported;
1943 _ = name;
1944}
1945
1946pub fn dump(elf: *Elf, tid: Zcu.PerThread.Id) void {
1947 const w = std.debug.lockStderrWriter(&.{});
1948 defer std.debug.unlockStderrWriter();
1949 elf.printNode(tid, w, .root, 0) catch {};
1950}
1951
1952pub fn printNode(
1953 elf: *Elf,
1954 tid: Zcu.PerThread.Id,
1955 w: *std.Io.Writer,
1956 ni: MappedFile.Node.Index,
1957 indent: usize,
1958) !void {
1959 const node = elf.getNode(ni);
1960 const mf_node = &elf.mf.nodes.items[@intFromEnum(ni)];
1961 const off, const size = mf_node.location().resolve(&elf.mf);
1962 try w.splatByteAll(' ', indent);
1963 try w.writeAll(@tagName(node));
1964 switch (node) {
1965 else => {},
1966 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),
1967 .nav => |nav_index| {
1968 const zcu = elf.base.comp.zcu.?;
1969 const ip = &zcu.intern_pool;
1970 const nav = ip.getNav(nav_index);
1971 try w.print("({f}, {f})", .{
1972 Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }),
1973 nav.fqn.fmt(ip),
1974 });
1975 },
1976 .uav => |uav| {
1977 const zcu = elf.base.comp.zcu.?;
1978 const val: Value = .fromInterned(uav);
1979 try w.print("({f}, {f})", .{
1980 val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }),
1981 val.fmtValue(.{ .zcu = zcu, .tid = tid }),
1982 });
1983 },
1984 }
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 },
2019 }
2020}
2021
2022const assert = std.debug.assert;
2023const builtin = @import("builtin");
2024const codegen = @import("../codegen.zig");
2025const Compilation = @import("../Compilation.zig");
2026const Elf = @This();
2027const InternPool = @import("../InternPool.zig");
2028const link = @import("../link.zig");
2029const log = std.log.scoped(.link);
2030const MappedFile = @import("MappedFile.zig");
2031const native_endian = builtin.cpu.arch.endian();
2032const std = @import("std");
2033const target_util = @import("../target.zig");
2034const Type = @import("../Type.zig");
2035const Value = @import("../Value.zig");
2036const Zcu = @import("../Zcu.zig");
src/link/MachO/ZigObject.zig+32-22
...@@ -784,22 +784,26 @@ pub fn updateFunc(...@@ -784,22 +784,26 @@ pub fn updateFunc(
784 const sym_index = try self.getOrCreateMetadataForNav(macho_file, func.owner_nav);784 const sym_index = try self.getOrCreateMetadataForNav(macho_file, func.owner_nav);
785 self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);785 self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
786786
787 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;787 var aw: std.Io.Writer.Allocating = .init(gpa);
788 defer code_buffer.deinit(gpa);788 defer aw.deinit();
789789
790 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;790 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;
791 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();791 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
792792
793 try codegen.emitFunction(793 codegen.emitFunction(
794 &macho_file.base,794 &macho_file.base,
795 pt,795 pt,
796 zcu.navSrcLoc(func.owner_nav),796 zcu.navSrcLoc(func.owner_nav),
797 func_index,797 func_index,
798 sym_index,
798 mir,799 mir,
799 &code_buffer,800 &aw.writer,
800 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,801 if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
801 );802 ) catch |err| switch (err) {
802 const code = code_buffer.items;803 error.WriteFailed => return error.OutOfMemory,
804 else => |e| return e,
805 };
806 const code = aw.written();
803807
804 const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code);808 const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code);
805 const old_rva, const old_alignment = blk: {809 const old_rva, const old_alignment = blk: {
...@@ -895,21 +899,24 @@ pub fn updateNav(...@@ -895,21 +899,24 @@ pub fn updateNav(
895 const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index);899 const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index);
896 self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);900 self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
897901
898 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;902 var aw: std.Io.Writer.Allocating = .init(zcu.gpa);
899 defer code_buffer.deinit(zcu.gpa);903 defer aw.deinit();
900904
901 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;905 var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;
902 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();906 defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
903907
904 try codegen.generateSymbol(908 codegen.generateSymbol(
905 &macho_file.base,909 &macho_file.base,
906 pt,910 pt,
907 zcu.navSrcLoc(nav_index),911 zcu.navSrcLoc(nav_index),
908 Value.fromInterned(nav_init),912 Value.fromInterned(nav_init),
909 &code_buffer,913 &aw.writer,
910 .{ .atom_index = sym_index },914 .{ .atom_index = sym_index },
911 );915 ) catch |err| switch (err) {
912 const code = code_buffer.items;916 error.WriteFailed => return error.OutOfMemory,
917 else => |e| return e,
918 };
919 const code = aw.written();
913920
914 const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code);921 const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code);
915 if (isThreadlocal(macho_file, nav_index))922 if (isThreadlocal(macho_file, nav_index))
...@@ -1198,21 +1205,24 @@ fn lowerConst(...@@ -1198,21 +1205,24 @@ fn lowerConst(
1198) !codegen.SymbolResult {1205) !codegen.SymbolResult {
1199 const gpa = macho_file.base.comp.gpa;1206 const gpa = macho_file.base.comp.gpa;
12001207
1201 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;1208 var aw: std.Io.Writer.Allocating = .init(gpa);
1202 defer code_buffer.deinit(gpa);1209 defer aw.deinit();
12031210
1204 const name_str = try self.addString(gpa, name);1211 const name_str = try self.addString(gpa, name);
1205 const sym_index = try self.newSymbolWithAtom(gpa, name_str, macho_file);1212 const sym_index = try self.newSymbolWithAtom(gpa, name_str, macho_file);
12061213
1207 try codegen.generateSymbol(1214 codegen.generateSymbol(
1208 &macho_file.base,1215 &macho_file.base,
1209 pt,1216 pt,
1210 src_loc,1217 src_loc,
1211 val,1218 val,
1212 &code_buffer,1219 &aw.writer,
1213 .{ .atom_index = sym_index },1220 .{ .atom_index = sym_index },
1214 );1221 ) catch |err| switch (err) {
1215 const code = code_buffer.items;1222 error.WriteFailed => return error.OutOfMemory,
1223 else => |e| return e,
1224 };
1225 const code = aw.written();
12161226
1217 const sym = &self.symbols.items[sym_index];1227 const sym = &self.symbols.items[sym_index];
1218 sym.out_n_sect = output_section_index;1228 sym.out_n_sect = output_section_index;
...@@ -1349,8 +1359,8 @@ fn updateLazySymbol(...@@ -1349,8 +1359,8 @@ fn updateLazySymbol(
1349 const gpa = zcu.gpa;1359 const gpa = zcu.gpa;
13501360
1351 var required_alignment: Atom.Alignment = .none;1361 var required_alignment: Atom.Alignment = .none;
1352 var code_buffer: std.ArrayListUnmanaged(u8) = .empty;1362 var aw: std.Io.Writer.Allocating = .init(gpa);
1353 defer code_buffer.deinit(gpa);1363 defer aw.deinit();
13541364
1355 const name_str = blk: {1365 const name_str = blk: {
1356 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{1366 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{
...@@ -1368,11 +1378,11 @@ fn updateLazySymbol(...@@ -1368,11 +1378,11 @@ fn updateLazySymbol(
1368 src,1378 src,
1369 lazy_sym,1379 lazy_sym,
1370 &required_alignment,1380 &required_alignment,
1371 &code_buffer,1381 &aw.writer,
1372 .none,1382 .none,
1373 .{ .atom_index = symbol_index },1383 .{ .atom_index = symbol_index },
1374 );1384 );
1375 const code = code_buffer.items;1385 const code = aw.written();
13761386
1377 const output_section_index = switch (lazy_sym.kind) {1387 const output_section_index = switch (lazy_sym.kind) {
1378 .code => macho_file.zig_text_sect_index.?,1388 .code => macho_file.zig_text_sect_index.?,
src/link/MappedFile.zig created+929
...@@ -0,0 +1,929 @@
1file: std.fs.File,
2flags: packed struct {
3 block_size: std.mem.Alignment,
4 copy_file_range_unsupported: bool,
5 fallocate_punch_hole_unsupported: bool,
6 fallocate_insert_range_unsupported: bool,
7},
8section: if (is_windows) windows.HANDLE else void,
9contents: []align(std.heap.page_size_min) u8,
10nodes: std.ArrayList(Node),
11free_ni: Node.Index,
12large: std.ArrayList(u64),
13updates: std.ArrayList(Node.Index),
14update_prog_node: std.Progress.Node,
15writers: std.SinglyLinkedList,
16
17pub const Error = std.posix.MMapError ||
18 std.posix.MRemapError ||
19 std.fs.File.SetEndPosError ||
20 std.fs.File.CopyRangeError ||
21 error{NotFile};
22
23pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile {
24 var mf: MappedFile = .{
25 .file = file,
26 .flags = undefined,
27 .section = if (is_windows) windows.INVALID_HANDLE_VALUE else {},
28 .contents = &.{},
29 .nodes = .empty,
30 .free_ni = .none,
31 .large = .empty,
32 .updates = .empty,
33 .update_prog_node = .none,
34 .writers = .{},
35 };
36 errdefer mf.deinit(gpa);
37 const size: u64, const blksize = if (is_windows)
38 .{ try windows.GetFileSizeEx(file.handle), 1 }
39 else stat: {
40 const stat = try std.posix.fstat(mf.file.handle);
41 if (!std.posix.S.ISREG(stat.mode)) return error.PathAlreadyExists;
42 break :stat .{ @bitCast(stat.size), stat.blksize };
43 };
44 mf.flags = .{
45 .block_size = .fromByteUnits(
46 std.math.ceilPowerOfTwoAssert(usize, @max(std.heap.pageSize(), blksize)),
47 ),
48 .copy_file_range_unsupported = false,
49 .fallocate_insert_range_unsupported = false,
50 .fallocate_punch_hole_unsupported = false,
51 };
52 try mf.nodes.ensureUnusedCapacity(gpa, 1);
53 assert(try mf.addNode(gpa, .{
54 .add_node = .{
55 .size = size,
56 .fixed = true,
57 },
58 }) == Node.Index.root);
59 try mf.ensureTotalCapacity(@intCast(size));
60 return mf;
61}
62
63pub fn deinit(mf: *MappedFile, gpa: std.mem.Allocator) void {
64 mf.unmap();
65 mf.nodes.deinit(gpa);
66 mf.large.deinit(gpa);
67 mf.updates.deinit(gpa);
68 mf.update_prog_node.end();
69 assert(mf.writers.first == null);
70 mf.* = undefined;
71}
72
73pub const Node = extern struct {
74 parent: Node.Index,
75 prev: Node.Index,
76 next: Node.Index,
77 first: Node.Index,
78 last: Node.Index,
79 flags: Flags,
80 location_payload: Location.Payload,
81
82 pub const Flags = packed struct(u32) {
83 location_tag: Location.Tag,
84 alignment: std.mem.Alignment,
85 /// Whether this node can be moved.
86 fixed: bool,
87 /// Whether this node has been moved.
88 moved: bool,
89 /// Whether this node has been resized.
90 resized: bool,
91 /// Whether this node might contain non-zero bytes.
92 has_content: bool,
93 unused: @Type(.{ .int = .{
94 .signedness = .unsigned,
95 .bits = 32 - @bitSizeOf(std.mem.Alignment) - 5,
96 } }) = 0,
97 };
98
99 pub const Location = union(enum(u1)) {
100 small: extern struct {
101 /// Relative to `parent`.
102 offset: u32,
103 size: u32,
104 },
105 large: extern struct {
106 index: usize,
107 unused: @Type(.{ .int = .{
108 .signedness = .unsigned,
109 .bits = 64 - @bitSizeOf(usize),
110 } }) = 0,
111 },
112
113 pub const Tag = @typeInfo(Location).@"union".tag_type.?;
114 pub const Payload = @Type(.{ .@"union" = .{
115 .layout = .@"extern",
116 .tag_type = null,
117 .fields = @typeInfo(Location).@"union".fields,
118 .decls = &.{},
119 } });
120
121 pub fn resolve(loc: Location, mf: *const MappedFile) [2]u64 {
122 return switch (loc) {
123 .small => |small| .{ small.offset, small.size },
124 .large => |large| mf.large.items[large.index..][0..2].*,
125 };
126 }
127 };
128
129 pub const Index = enum(u32) {
130 none,
131 _,
132
133 pub const root: Node.Index = .none;
134
135 fn get(ni: Node.Index, mf: *const MappedFile) *Node {
136 return &mf.nodes.items[@intFromEnum(ni)];
137 }
138
139 pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void {
140 var child_ni = ni.get(mf).last;
141 while (child_ni != .none) {
142 try child_ni.moved(gpa, mf);
143 child_ni = child_ni.get(mf).prev;
144 }
145 }
146
147 pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool {
148 var parent_ni = ni;
149 while (parent_ni != .none) {
150 const parent = parent_ni.get(mf);
151 if (parent.flags.moved) return true;
152 parent_ni = parent.parent;
153 }
154 return false;
155 }
156 pub fn moved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void {
157 try mf.updates.ensureUnusedCapacity(gpa, 1);
158 ni.movedAssumeCapacity(mf);
159 }
160 pub fn cleanMoved(ni: Node.Index, mf: *const MappedFile) bool {
161 const node_moved = &ni.get(mf).flags.moved;
162 defer node_moved.* = false;
163 return node_moved.*;
164 }
165 fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
166 var parent_ni = ni;
167 while (parent_ni != .none) {
168 const parent_node = parent_ni.get(mf);
169 if (parent_node.flags.moved) return;
170 parent_ni = parent_node.parent;
171 }
172 const node = ni.get(mf);
173 node.flags.moved = true;
174 if (node.flags.resized) return;
175 mf.updates.appendAssumeCapacity(ni);
176 mf.update_prog_node.increaseEstimatedTotalItems(1);
177 }
178
179 pub fn hasResized(ni: Node.Index, mf: *const MappedFile) bool {
180 return ni.get(mf).flags.resized;
181 }
182 pub fn resized(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void {
183 try mf.updates.ensureUnusedCapacity(gpa, 1);
184 ni.resizedAssumeCapacity(mf);
185 }
186 pub fn cleanResized(ni: Node.Index, mf: *const MappedFile) bool {
187 const node_resized = &ni.get(mf).flags.resized;
188 defer node_resized.* = false;
189 return node_resized.*;
190 }
191 fn resizedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
192 const node = ni.get(mf);
193 if (node.flags.resized) return;
194 node.flags.resized = true;
195 if (node.flags.moved) return;
196 mf.updates.appendAssumeCapacity(ni);
197 mf.update_prog_node.increaseEstimatedTotalItems(1);
198 }
199
200 pub fn alignment(ni: Node.Index, mf: *const MappedFile) std.mem.Alignment {
201 return ni.get(mf).flags.alignment;
202 }
203
204 fn setLocationAssumeCapacity(ni: Node.Index, mf: *MappedFile, offset: u64, size: u64) void {
205 const node = ni.get(mf);
206 if (size == 0) node.flags.has_content = false;
207 switch (node.location()) {
208 .small => |small| {
209 if (small.offset != offset) ni.movedAssumeCapacity(mf);
210 if (small.size != size) ni.resizedAssumeCapacity(mf);
211 if (std.math.cast(u32, offset)) |small_offset| {
212 if (std.math.cast(u32, size)) |small_size| {
213 node.location_payload.small = .{
214 .offset = small_offset,
215 .size = small_size,
216 };
217 return;
218 }
219 }
220 defer mf.large.appendSliceAssumeCapacity(&.{ offset, size });
221 node.flags.location_tag = .large;
222 node.location_payload = .{ .large = .{ .index = mf.large.items.len } };
223 },
224 .large => |large| {
225 const large_items = mf.large.items[large.index..][0..2];
226 if (large_items[0] != offset) ni.movedAssumeCapacity(mf);
227 if (large_items[1] != size) ni.resizedAssumeCapacity(mf);
228 large_items.* = .{ offset, size };
229 },
230 }
231 }
232
233 pub fn location(ni: Node.Index, mf: *const MappedFile) Location {
234 return ni.get(mf).location();
235 }
236
237 pub fn fileLocation(
238 ni: Node.Index,
239 mf: *const MappedFile,
240 set_has_content: bool,
241 ) struct { offset: u64, size: u64 } {
242 var offset, const size = ni.location(mf).resolve(mf);
243 var parent_ni = ni;
244 while (true) {
245 const parent = parent_ni.get(mf);
246 if (set_has_content) parent.flags.has_content = true;
247 if (parent_ni == .none) break;
248 parent_ni = parent.parent;
249 offset += parent_ni.location(mf).resolve(mf)[0];
250 }
251 return .{ .offset = offset, .size = size };
252 }
253
254 pub fn slice(ni: Node.Index, mf: *const MappedFile) []u8 {
255 const file_loc = ni.fileLocation(mf, true);
256 return mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
257 }
258
259 pub fn sliceConst(ni: Node.Index, mf: *const MappedFile) []const u8 {
260 const file_loc = ni.fileLocation(mf, false);
261 return mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)];
262 }
263
264 pub fn resize(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, size: u64) !void {
265 try mf.resizeNode(gpa, ni, size);
266 var writers_it = mf.writers.first;
267 while (writers_it) |writer_node| : (writers_it = writer_node.next) {
268 const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node);
269 w.interface.buffer = w.ni.slice(mf);
270 }
271 }
272
273 pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void {
274 w.* = .{
275 .gpa = gpa,
276 .mf = mf,
277 .writer_node = .{},
278 .ni = ni,
279 .interface = .{
280 .buffer = ni.slice(mf),
281 .vtable = &Writer.vtable,
282 },
283 .err = null,
284 };
285 mf.writers.prepend(&w.writer_node);
286 }
287 };
288
289 pub fn location(node: *const Node) Location {
290 return switch (node.flags.location_tag) {
291 inline else => |tag| @unionInit(
292 Location,
293 @tagName(tag),
294 @field(node.location_payload, @tagName(tag)),
295 ),
296 };
297 }
298
299 pub const Writer = struct {
300 gpa: std.mem.Allocator,
301 mf: *MappedFile,
302 writer_node: std.SinglyLinkedList.Node,
303 ni: Node.Index,
304 interface: std.Io.Writer,
305 err: ?Error,
306
307 pub fn deinit(w: *Writer) void {
308 assert(w.mf.writers.popFirst() == &w.writer_node);
309 w.* = undefined;
310 }
311
312 const vtable: std.Io.Writer.VTable = .{
313 .drain = drain,
314 .sendFile = sendFile,
315 .flush = std.Io.Writer.noopFlush,
316 .rebase = growingRebase,
317 };
318
319 fn drain(
320 interface: *std.Io.Writer,
321 data: []const []const u8,
322 splat: usize,
323 ) std.Io.Writer.Error!usize {
324 const pattern = data[data.len - 1];
325 const splat_len = pattern.len * splat;
326 const start_len = interface.end;
327 assert(data.len != 0);
328 for (data) |bytes| {
329 try growingRebase(interface, interface.end, bytes.len + splat_len + 1);
330 @memcpy(interface.buffer[interface.end..][0..bytes.len], bytes);
331 interface.end += bytes.len;
332 }
333 if (splat == 0) {
334 interface.end -= pattern.len;
335 } else switch (pattern.len) {
336 0 => {},
337 1 => {
338 @memset(interface.buffer[interface.end..][0 .. splat - 1], pattern[0]);
339 interface.end += splat - 1;
340 },
341 else => for (0..splat - 1) |_| {
342 @memcpy(interface.buffer[interface.end..][0..pattern.len], pattern);
343 interface.end += pattern.len;
344 },
345 }
346 return interface.end - start_len;
347 }
348
349 fn sendFile(
350 interface: *std.Io.Writer,
351 file_reader: *std.fs.File.Reader,
352 limit: std.Io.Limit,
353 ) std.Io.Writer.FileError!usize {
354 if (limit == .nothing) return 0;
355 const pos = file_reader.logicalPos();
356 const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line;
357 if (additional == 0) return error.EndOfStream;
358 try growingRebase(interface, interface.end, limit.minInt64(additional));
359 switch (file_reader.mode) {
360 .positional => {
361 const fr_buf = file_reader.interface.buffered();
362 const buf_copy_size = interface.write(fr_buf) catch unreachable;
363 file_reader.interface.toss(buf_copy_size);
364 if (buf_copy_size < fr_buf.len) return buf_copy_size;
365 assert(file_reader.logicalPos() == file_reader.pos);
366
367 const w: *Writer = @fieldParentPtr("interface", interface);
368 const copy_size: usize = @intCast(w.mf.copyFileRange(
369 file_reader.file,
370 file_reader.pos,
371 w.ni.fileLocation(w.mf, true).offset + interface.end,
372 limit.minInt(interface.unusedCapacityLen()),
373 ) catch |err| {
374 w.err = err;
375 return error.WriteFailed;
376 });
377 interface.end += copy_size;
378 return copy_size;
379 },
380 .streaming,
381 .streaming_reading,
382 .positional_reading,
383 .failure,
384 => {
385 const dest = limit.slice(interface.unusedCapacitySlice());
386 const n = try file_reader.read(dest);
387 interface.end += n;
388 return n;
389 },
390 }
391 }
392
393 fn growingRebase(
394 interface: *std.Io.Writer,
395 preserve: usize,
396 unused_capacity: usize,
397 ) std.Io.Writer.Error!void {
398 _ = preserve;
399 const total_capacity = interface.end + unused_capacity;
400 if (interface.buffer.len >= total_capacity) return;
401 const w: *Writer = @fieldParentPtr("interface", interface);
402 w.ni.resize(w.mf, w.gpa, total_capacity +| total_capacity / 2) catch |err| {
403 w.err = err;
404 return error.WriteFailed;
405 };
406 }
407 };
408
409 comptime {
410 if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 32);
411 }
412};
413
414fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
415 parent: Node.Index = .none,
416 prev: Node.Index = .none,
417 next: Node.Index = .none,
418 offset: u64 = 0,
419 add_node: AddNodeOptions,
420}) !Node.Index {
421 if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1);
422 const offset = opts.add_node.alignment.forward(@intCast(opts.offset));
423 const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: {
424 if (std.math.cast(u32, offset)) |small_offset| break :location .{ .small, .{
425 .small = .{ .offset = small_offset, .size = 0 },
426 } };
427 try mf.large.ensureUnusedCapacity(gpa, 2);
428 defer mf.large.appendSliceAssumeCapacity(&.{ offset, 0 });
429 break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } };
430 };
431 const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) {
432 .none => .{ @enumFromInt(mf.nodes.items.len), mf.nodes.addOneAssumeCapacity() },
433 else => |free_ni| {
434 const free_node = free_ni.get(mf);
435 mf.free_ni = free_node.next;
436 break :free .{ free_ni, free_node };
437 },
438 };
439 free_node.* = .{
440 .parent = opts.parent,
441 .prev = opts.prev,
442 .next = opts.next,
443 .first = .none,
444 .last = .none,
445 .flags = .{
446 .location_tag = location_tag,
447 .alignment = opts.add_node.alignment,
448 .fixed = opts.add_node.fixed,
449 .moved = true,
450 .resized = true,
451 .has_content = false,
452 },
453 .location_payload = location_payload,
454 };
455 {
456 defer {
457 free_node.flags.moved = false;
458 free_node.flags.resized = false;
459 }
460 if (offset > opts.parent.location(mf).resolve(mf)[1]) try opts.parent.resize(mf, gpa, offset);
461 try free_ni.resize(mf, gpa, opts.add_node.size);
462 }
463 if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf);
464 if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf);
465 return free_ni;
466}
467
468pub const AddNodeOptions = struct {
469 size: u64 = 0,
470 alignment: std.mem.Alignment = .@"1",
471 fixed: bool = false,
472 moved: bool = false,
473 resized: bool = false,
474};
475
476pub fn addOnlyChildNode(
477 mf: *MappedFile,
478 gpa: std.mem.Allocator,
479 parent_ni: Node.Index,
480 opts: AddNodeOptions,
481) !Node.Index {
482 try mf.nodes.ensureUnusedCapacity(gpa, 1);
483 const parent = parent_ni.get(mf);
484 assert(parent.first == .none and parent.last == .none);
485 const ni = try mf.addNode(gpa, .{
486 .parent = parent_ni,
487 .add_node = opts,
488 });
489 parent.first = ni;
490 parent.last = ni;
491 return ni;
492}
493
494pub fn addLastChildNode(
495 mf: *MappedFile,
496 gpa: std.mem.Allocator,
497 parent_ni: Node.Index,
498 opts: AddNodeOptions,
499) !Node.Index {
500 try mf.nodes.ensureUnusedCapacity(gpa, 1);
501 const parent = parent_ni.get(mf);
502 const ni = try mf.addNode(gpa, .{
503 .parent = parent_ni,
504 .prev = parent.last,
505 .offset = offset: switch (parent.last) {
506 .none => 0,
507 else => |last_ni| {
508 const last_offset, const last_size = last_ni.location(mf).resolve(mf);
509 break :offset last_offset + last_size;
510 },
511 },
512 .add_node = opts,
513 });
514 switch (parent.last) {
515 .none => parent.first = ni,
516 else => |last_ni| last_ni.get(mf).next = ni,
517 }
518 parent.last = ni;
519 return ni;
520}
521
522pub fn addNodeAfter(
523 mf: *MappedFile,
524 gpa: std.mem.Allocator,
525 prev_ni: Node.Index,
526 opts: AddNodeOptions,
527) !Node.Index {
528 assert(prev_ni != .none);
529 try mf.nodes.ensureUnusedCapacity(gpa, 1);
530 const prev = prev_ni.get(mf);
531 const prev_offset, const prev_size = prev.location().resolve(mf);
532 const ni = try mf.addNode(gpa, .{
533 .parent = prev.parent,
534 .prev = prev_ni,
535 .next = prev.next,
536 .offset = prev_offset + prev_size,
537 .add_node = opts,
538 });
539 switch (prev.next) {
540 .none => prev.parent.get(mf).last = ni,
541 else => |next_ni| next_ni.get(mf).prev = ni,
542 }
543 prev.next = ni;
544 return ni;
545}
546
547fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) !void {
548 const node = ni.get(mf);
549 var old_offset, const old_size = node.location().resolve(mf);
550 const new_size = node.flags.alignment.forward(@intCast(requested_size));
551 // Resize the entire file
552 if (ni == Node.Index.root) {
553 try mf.file.setEndPos(new_size);
554 try mf.ensureTotalCapacity(@intCast(new_size));
555 try mf.ensureCapacityForSetLocation(gpa);
556 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
557 return;
558 }
559 while (true) {
560 const parent = node.parent.get(mf);
561 _, const old_parent_size = parent.location().resolve(mf);
562 const trailing_end = switch (node.next) {
563 .none => parent.location().resolve(mf)[1],
564 else => |next_ni| next_ni.location(mf).resolve(mf)[0],
565 };
566 assert(old_offset + old_size <= trailing_end);
567 // Expand the node into available trailing free space
568 if (old_offset + new_size <= trailing_end) {
569 try mf.ensureCapacityForSetLocation(gpa);
570 ni.setLocationAssumeCapacity(mf, old_offset, new_size);
571 return;
572 }
573 // Ask the filesystem driver to insert an extent into the file without copying any data
574 if (is_linux and !mf.flags.fallocate_insert_range_unsupported and
575 node.flags.alignment.order(mf.flags.block_size).compare(.gte))
576 insert_range: {
577 const last_offset, const last_size = parent.last.location(mf).resolve(mf);
578 const last_end = last_offset + last_size;
579 assert(last_end <= old_parent_size);
580 const range_size =
581 node.flags.alignment.forward(@intCast(requested_size +| requested_size / 2)) - old_size;
582 const new_parent_size = last_end + range_size;
583 if (new_parent_size > old_parent_size) {
584 try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / 2);
585 continue;
586 }
587 const range_file_offset = ni.fileLocation(mf, false).offset + old_size;
588 retry: while (true) {
589 switch (linux.E.init(linux.fallocate(
590 mf.file.handle,
591 linux.FALLOC.FL_INSERT_RANGE,
592 @intCast(range_file_offset),
593 @intCast(range_size),
594 ))) {
595 .SUCCESS => {
596 var enclosing_ni = ni;
597 while (enclosing_ni != .none) {
598 try mf.ensureCapacityForSetLocation(gpa);
599 const enclosing = enclosing_ni.get(mf);
600 const enclosing_offset, const enclosing_size =
601 enclosing.location().resolve(mf);
602 enclosing_ni.setLocationAssumeCapacity(
603 mf,
604 enclosing_offset,
605 enclosing_size + range_size,
606 );
607 var after_ni = enclosing.next;
608 while (after_ni != .none) {
609 try mf.ensureCapacityForSetLocation(gpa);
610 const after = after_ni.get(mf);
611 const after_offset, const after_size = after.location().resolve(mf);
612 after_ni.setLocationAssumeCapacity(
613 mf,
614 range_size + after_offset,
615 after_size,
616 );
617 after_ni = after.next;
618 }
619 enclosing_ni = enclosing.parent;
620 }
621 return;
622 },
623 .INTR => continue :retry,
624 .BADF, .FBIG, .INVAL => unreachable,
625 .IO => return error.InputOutput,
626 .NODEV => return error.NotFile,
627 .NOSPC => return error.NoSpaceLeft,
628 .NOSYS, .OPNOTSUPP => {
629 mf.flags.fallocate_insert_range_unsupported = true;
630 break :insert_range;
631 },
632 .PERM => return error.PermissionDenied,
633 .SPIPE => return error.Unseekable,
634 .TXTBSY => return error.FileBusy,
635 else => |e| return std.posix.unexpectedErrno(e),
636 }
637 }
638 }
639 switch (node.next) {
640 .none => {
641 // As this is the last node, we simply need more space in the parent
642 const new_parent_size = old_offset + new_size;
643 try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / 2);
644 },
645 else => |*next_ni_ptr| switch (node.flags.fixed) {
646 false => {
647 // Make space at the end of the parent for this floating node
648 const last = parent.last.get(mf);
649 const last_offset, const last_size = last.location().resolve(mf);
650 const new_offset = node.flags.alignment.forward(@intCast(last_offset + last_size));
651 const new_parent_size = new_offset + new_size;
652 if (new_parent_size > old_parent_size) {
653 try mf.resizeNode(
654 gpa,
655 node.parent,
656 new_parent_size +| new_parent_size / 2,
657 );
658 continue;
659 }
660 const next_ni = next_ni_ptr.*;
661 next_ni.get(mf).prev = node.prev;
662 switch (node.prev) {
663 .none => parent.first = next_ni,
664 else => |prev_ni| prev_ni.get(mf).next = next_ni,
665 }
666 last.next = ni;
667 node.prev = parent.last;
668 next_ni_ptr.* = .none;
669 parent.last = ni;
670 if (node.flags.has_content) {
671 const parent_file_offset = node.parent.fileLocation(mf, false).offset;
672 try mf.moveRange(
673 parent_file_offset + old_offset,
674 parent_file_offset + new_offset,
675 old_size,
676 );
677 }
678 old_offset = new_offset;
679 },
680 true => {
681 // Move the next floating node to make space for this fixed node
682 const next_ni = next_ni_ptr.*;
683 const next = next_ni.get(mf);
684 assert(!next.flags.fixed);
685 const next_offset, const next_size = next.location().resolve(mf);
686 const last = parent.last.get(mf);
687 const last_offset, const last_size = last.location().resolve(mf);
688 const new_offset = next.flags.alignment.forward(@intCast(
689 @max(old_offset + new_size, last_offset + last_size),
690 ));
691 const new_parent_size = new_offset + next_size;
692 if (new_parent_size > old_parent_size) {
693 try mf.resizeNode(
694 gpa,
695 node.parent,
696 new_parent_size +| new_parent_size / 2,
697 );
698 continue;
699 }
700 try mf.ensureCapacityForSetLocation(gpa);
701 next.prev = parent.last;
702 parent.last = next_ni;
703 last.next = next_ni;
704 next_ni_ptr.* = next.next;
705 switch (next.next) {
706 .none => {},
707 else => |next_next_ni| next_next_ni.get(mf).prev = ni,
708 }
709 next.next = .none;
710 if (node.flags.has_content) {
711 const parent_file_offset = node.parent.fileLocation(mf, false).offset;
712 try mf.moveRange(
713 parent_file_offset + next_offset,
714 parent_file_offset + new_offset,
715 next_size,
716 );
717 }
718 next_ni.setLocationAssumeCapacity(mf, new_offset, next_size);
719 },
720 },
721 }
722 }
723}
724
725fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) !void {
726 // make a copy of this node at the new location
727 try mf.copyRange(old_file_offset, new_file_offset, size);
728 // delete the copy of this node at the old location
729 if (is_linux and !mf.flags.fallocate_punch_hole_unsupported and
730 size >= mf.flags.block_size.toByteUnits() * 2 - 1) while (true)
731 {
732 switch (linux.E.init(linux.fallocate(
733 mf.file.handle,
734 linux.FALLOC.FL_PUNCH_HOLE | linux.FALLOC.FL_KEEP_SIZE,
735 @intCast(old_file_offset),
736 @intCast(size),
737 ))) {
738 .SUCCESS => return,
739 .INTR => continue,
740 .BADF, .FBIG, .INVAL => unreachable,
741 .IO => return error.InputOutput,
742 .NODEV => return error.NotFile,
743 .NOSPC => return error.NoSpaceLeft,
744 .NOSYS, .OPNOTSUPP => {
745 mf.flags.fallocate_punch_hole_unsupported = true;
746 break;
747 },
748 .PERM => return error.PermissionDenied,
749 .SPIPE => return error.Unseekable,
750 .TXTBSY => return error.FileBusy,
751 else => |e| return std.posix.unexpectedErrno(e),
752 }
753 };
754 @memset(mf.contents[@intCast(old_file_offset)..][0..@intCast(size)], 0);
755}
756
757fn copyRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) !void {
758 const copy_size = try mf.copyFileRange(mf.file, old_file_offset, new_file_offset, size);
759 if (copy_size < size) @memcpy(
760 mf.contents[@intCast(new_file_offset + copy_size)..][0..@intCast(size - copy_size)],
761 mf.contents[@intCast(old_file_offset + copy_size)..][0..@intCast(size - copy_size)],
762 );
763}
764
765fn copyFileRange(
766 mf: *MappedFile,
767 old_file: std.fs.File,
768 old_file_offset: u64,
769 new_file_offset: u64,
770 size: u64,
771) !u64 {
772 var remaining_size = size;
773 if (is_linux and !mf.flags.copy_file_range_unsupported) {
774 var old_file_offset_mut: i64 = @intCast(old_file_offset);
775 var new_file_offset_mut: i64 = @intCast(new_file_offset);
776 while (remaining_size >= mf.flags.block_size.toByteUnits() * 2 - 1) {
777 const copy_len = linux.copy_file_range(
778 old_file.handle,
779 &old_file_offset_mut,
780 mf.file.handle,
781 &new_file_offset_mut,
782 @intCast(remaining_size),
783 0,
784 );
785 switch (linux.E.init(copy_len)) {
786 .SUCCESS => {
787 if (copy_len == 0) break;
788 remaining_size -= copy_len;
789 if (remaining_size == 0) break;
790 },
791 .INTR => continue,
792 .BADF, .FBIG, .INVAL, .OVERFLOW => unreachable,
793 .IO => return error.InputOutput,
794 .ISDIR => return error.IsDir,
795 .NOMEM => return error.SystemResources,
796 .NOSPC => return error.NoSpaceLeft,
797 .NOSYS, .OPNOTSUPP, .XDEV => {
798 mf.flags.copy_file_range_unsupported = true;
799 break;
800 },
801 .PERM => return error.PermissionDenied,
802 .TXTBSY => return error.FileBusy,
803 else => |e| return std.posix.unexpectedErrno(e),
804 }
805 }
806 }
807 return size - remaining_size;
808}
809
810fn ensureCapacityForSetLocation(mf: *MappedFile, gpa: std.mem.Allocator) !void {
811 try mf.large.ensureUnusedCapacity(gpa, 2);
812 try mf.updates.ensureUnusedCapacity(gpa, 1);
813}
814
815pub fn ensureTotalCapacity(mf: *MappedFile, new_capacity: usize) !void {
816 if (mf.contents.len >= new_capacity) return;
817 try mf.ensureTotalCapacityPrecise(new_capacity +| new_capacity / 2);
818}
819
820pub fn ensureTotalCapacityPrecise(mf: *MappedFile, new_capacity: usize) !void {
821 if (mf.contents.len >= new_capacity) return;
822 const aligned_capacity = mf.flags.block_size.forward(new_capacity);
823 if (!is_linux) mf.unmap() else if (mf.contents.len > 0) {
824 mf.contents = try std.posix.mremap(
825 mf.contents.ptr,
826 mf.contents.len,
827 aligned_capacity,
828 .{ .MAYMOVE = true },
829 null,
830 );
831 return;
832 }
833 if (is_windows) {
834 if (mf.section == windows.INVALID_HANDLE_VALUE) switch (windows.ntdll.NtCreateSection(
835 &mf.section,
836 windows.STANDARD_RIGHTS_REQUIRED | windows.SECTION_QUERY |
837 windows.SECTION_MAP_WRITE | windows.SECTION_MAP_READ | windows.SECTION_EXTEND_SIZE,
838 null,
839 @constCast(&@as(i64, @intCast(aligned_capacity))),
840 windows.PAGE_READWRITE,
841 windows.SEC_COMMIT,
842 mf.file.handle,
843 )) {
844 .SUCCESS => {},
845 else => return error.MemoryMappingNotSupported,
846 };
847 var contents_ptr: ?[*]align(std.heap.page_size_min) u8 = null;
848 var contents_len = aligned_capacity;
849 switch (windows.ntdll.NtMapViewOfSection(
850 mf.section,
851 windows.GetCurrentProcess(),
852 @ptrCast(&contents_ptr),
853 null,
854 0,
855 null,
856 &contents_len,
857 .ViewUnmap,
858 0,
859 windows.PAGE_READWRITE,
860 )) {
861 .SUCCESS => mf.contents = contents_ptr.?[0..contents_len],
862 else => return error.MemoryMappingNotSupported,
863 }
864 } else mf.contents = try std.posix.mmap(
865 null,
866 aligned_capacity,
867 std.posix.PROT.READ | std.posix.PROT.WRITE,
868 .{ .TYPE = if (is_linux) .SHARED_VALIDATE else .SHARED },
869 mf.file.handle,
870 0,
871 );
872}
873
874pub fn unmap(mf: *MappedFile) void {
875 if (mf.contents.len == 0) return;
876 if (is_windows)
877 _ = windows.ntdll.NtUnmapViewOfSection(windows.GetCurrentProcess(), mf.contents.ptr)
878 else
879 std.posix.munmap(mf.contents);
880 mf.contents = &.{};
881 if (is_windows and mf.section != windows.INVALID_HANDLE_VALUE) {
882 windows.CloseHandle(mf.section);
883 mf.section = windows.INVALID_HANDLE_VALUE;
884 }
885}
886
887fn verify(mf: *MappedFile) void {
888 const root = Node.Index.root.get(mf);
889 assert(root.parent == .none);
890 assert(root.prev == .none);
891 assert(root.next == .none);
892 mf.verifyNode(Node.Index.root);
893}
894
895fn verifyNode(mf: *MappedFile, parent_ni: Node.Index) void {
896 const parent = parent_ni.get(mf);
897 const parent_offset, const parent_size = parent.location().resolve(mf);
898 var prev_ni: Node.Index = .none;
899 var prev_end: u64 = 0;
900 var ni = parent.first;
901 while (true) {
902 if (ni == .none) {
903 assert(parent.last == prev_ni);
904 return;
905 }
906 const node = ni.get(mf);
907 assert(node.parent == parent_ni);
908 const offset, const size = node.location().resolve(mf);
909 assert(node.flags.alignment.check(@intCast(offset)));
910 assert(node.flags.alignment.check(@intCast(size)));
911 const end = offset + size;
912 assert(end <= parent_offset + parent_size);
913 assert(offset >= prev_end);
914 assert(node.prev == prev_ni);
915 mf.verifyNode(ni);
916 prev_ni = ni;
917 prev_end = end;
918 ni = node.next;
919 }
920}
921
922const assert = std.debug.assert;
923const builtin = @import("builtin");
924const is_linux = builtin.os.tag == .linux;
925const is_windows = builtin.os.tag == .windows;
926const linux = std.os.linux;
927const MappedFile = @This();
928const std = @import("std");
929const windows = std.os.windows;
src/link/Queue.zig+56-24
...@@ -22,17 +22,17 @@ prelink_wait_count: u32,...@@ -22,17 +22,17 @@ prelink_wait_count: u32,
2222
23/// Prelink tasks which have been enqueued and are not yet owned by the worker thread.23/// Prelink tasks which have been enqueued and are not yet owned by the worker thread.
24/// Allocated into `gpa`, guarded by `mutex`.24/// Allocated into `gpa`, guarded by `mutex`.
25queued_prelink: std.ArrayListUnmanaged(PrelinkTask),25queued_prelink: std.ArrayList(PrelinkTask),
26/// The worker thread moves items from `queued_prelink` into this array in order to process them.26/// The worker thread moves items from `queued_prelink` into this array in order to process them.
27/// Allocated into `gpa`, accessed only by the worker thread.27/// Allocated into `gpa`, accessed only by the worker thread.
28wip_prelink: std.ArrayListUnmanaged(PrelinkTask),28wip_prelink: std.ArrayList(PrelinkTask),
2929
30/// Like `queued_prelink`, but for ZCU tasks.30/// Like `queued_prelink`, but for ZCU tasks.
31/// Allocated into `gpa`, guarded by `mutex`.31/// Allocated into `gpa`, guarded by `mutex`.
32queued_zcu: std.ArrayListUnmanaged(ZcuTask),32queued_zcu: std.ArrayList(ZcuTask),
33/// Like `wip_prelink`, but for ZCU tasks.33/// Like `wip_prelink`, but for ZCU tasks.
34/// Allocated into `gpa`, accessed only by the worker thread.34/// Allocated into `gpa`, accessed only by the worker thread.
35wip_zcu: std.ArrayListUnmanaged(ZcuTask),35wip_zcu: std.ArrayList(ZcuTask),
3636
37/// When processing ZCU link tasks, we might have to block due to unpopulated MIR. When this37/// When processing ZCU link tasks, we might have to block due to unpopulated MIR. When this
38/// happens, some tasks in `wip_zcu` have been run, and some are still pending. This is the38/// happens, some tasks in `wip_zcu` have been run, and some are still pending. This is the
...@@ -213,32 +213,41 @@ pub fn enqueueZcu(q: *Queue, comp: *Compilation, task: ZcuTask) Allocator.Error!...@@ -213,32 +213,41 @@ pub fn enqueueZcu(q: *Queue, comp: *Compilation, task: ZcuTask) Allocator.Error!
213213
214fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {214fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {
215 q.flush_safety.lock(); // every `return` site should unlock this before unlocking `q.mutex`215 q.flush_safety.lock(); // every `return` site should unlock this before unlocking `q.mutex`
216
217 if (std.debug.runtime_safety) {216 if (std.debug.runtime_safety) {
218 q.mutex.lock();217 q.mutex.lock();
219 defer q.mutex.unlock();218 defer q.mutex.unlock();
220 assert(q.state == .running);219 assert(q.state == .running);
221 }220 }
221
222 var have_idle_tasks = true;
222 prelink: while (true) {223 prelink: while (true) {
223 assert(q.wip_prelink.items.len == 0);224 assert(q.wip_prelink.items.len == 0);
224 {225 swap_queues: while (true) {
225 q.mutex.lock();226 {
226 defer q.mutex.unlock();227 q.mutex.lock();
227 std.mem.swap(std.ArrayListUnmanaged(PrelinkTask), &q.queued_prelink, &q.wip_prelink);228 defer q.mutex.unlock();
228 if (q.wip_prelink.items.len == 0) {229 std.mem.swap(std.ArrayList(PrelinkTask), &q.queued_prelink, &q.wip_prelink);
229 if (q.prelink_wait_count == 0) {230 if (q.wip_prelink.items.len > 0) break :swap_queues;
230 break :prelink; // prelink is done231 if (q.prelink_wait_count == 0) break :prelink; // prelink is done
231 } else {232 if (!have_idle_tasks) {
232 // We're expecting more prelink tasks so can't move on to ZCU tasks.233 // We're expecting more prelink tasks so can't move on to ZCU tasks.
233 q.state = .finished;234 q.state = .finished;
234 q.flush_safety.unlock();235 q.flush_safety.unlock();
235 return;236 return;
236 }237 }
237 }238 }
239 have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) {
240 error.OutOfMemory => have_idle_tasks: {
241 comp.link_diags.setAllocFailure();
242 break :have_idle_tasks false;
243 },
244 error.LinkFailure => false,
245 };
238 }246 }
239 for (q.wip_prelink.items) |task| {247 for (q.wip_prelink.items) |task| {
240 link.doPrelinkTask(comp, task);248 link.doPrelinkTask(comp, task);
241 }249 }
250 have_idle_tasks = true;
242 q.wip_prelink.clearRetainingCapacity();251 q.wip_prelink.clearRetainingCapacity();
243 }252 }
244253
...@@ -256,17 +265,29 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {...@@ -256,17 +265,29 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {
256265
257 // Now we can run ZCU tasks.266 // Now we can run ZCU tasks.
258 while (true) {267 while (true) {
259 if (q.wip_zcu.items.len == q.wip_zcu_idx) {268 if (q.wip_zcu.items.len == q.wip_zcu_idx) swap_queues: {
260 q.wip_zcu.clearRetainingCapacity();269 q.wip_zcu.clearRetainingCapacity();
261 q.wip_zcu_idx = 0;270 q.wip_zcu_idx = 0;
262 q.mutex.lock();271 while (true) {
263 defer q.mutex.unlock();272 {
264 std.mem.swap(std.ArrayListUnmanaged(ZcuTask), &q.queued_zcu, &q.wip_zcu);273 q.mutex.lock();
265 if (q.wip_zcu.items.len == 0) {274 defer q.mutex.unlock();
266 // We've exhausted all available tasks.275 std.mem.swap(std.ArrayList(ZcuTask), &q.queued_zcu, &q.wip_zcu);
267 q.state = .finished;276 if (q.wip_zcu.items.len > 0) break :swap_queues;
268 q.flush_safety.unlock();277 if (!have_idle_tasks) {
269 return;278 // We've exhausted all available tasks.
279 q.state = .finished;
280 q.flush_safety.unlock();
281 return;
282 }
283 }
284 have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) {
285 error.OutOfMemory => have_idle_tasks: {
286 comp.link_diags.setAllocFailure();
287 break :have_idle_tasks false;
288 },
289 error.LinkFailure => false,
290 };
270 }291 }
271 }292 }
272 const task = q.wip_zcu.items[q.wip_zcu_idx];293 const task = q.wip_zcu.items[q.wip_zcu_idx];
...@@ -274,8 +295,18 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {...@@ -274,8 +295,18 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {
274 pending: {295 pending: {
275 if (task != .link_func) break :pending;296 if (task != .link_func) break :pending;
276 const status_ptr = &task.link_func.mir.status;297 const status_ptr = &task.link_func.mir.status;
277 // First check without the mutex to optimize for the common case where MIR is ready.298 while (true) {
278 if (status_ptr.load(.acquire) != .pending) break :pending;299 // First check without the mutex to optimize for the common case where MIR is ready.
300 if (status_ptr.load(.acquire) != .pending) break :pending;
301 if (have_idle_tasks) have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) {
302 error.OutOfMemory => have_idle_tasks: {
303 comp.link_diags.setAllocFailure();
304 break :have_idle_tasks false;
305 },
306 error.LinkFailure => false,
307 };
308 if (!have_idle_tasks) break;
309 }
279 q.mutex.lock();310 q.mutex.lock();
280 defer q.mutex.unlock();311 defer q.mutex.unlock();
281 if (status_ptr.load(.acquire) != .pending) break :pending;312 if (status_ptr.load(.acquire) != .pending) break :pending;
...@@ -298,6 +329,7 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {...@@ -298,6 +329,7 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void {
298 }329 }
299 }330 }
300 q.wip_zcu_idx += 1;331 q.wip_zcu_idx += 1;
332 have_idle_tasks = true;
301 }333 }
302}334}
303335
src/link/Wasm.zig+8-1
...@@ -4257,7 +4257,14 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu...@@ -4257,7 +4257,14 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu
4257 const func_table_fixups_start: u32 = @intCast(wasm.func_table_fixups.items.len);4257 const func_table_fixups_start: u32 = @intCast(wasm.func_table_fixups.items.len);
4258 wasm.string_bytes_lock.lock();4258 wasm.string_bytes_lock.lock();
42594259
4260 try codegen.generateSymbol(&wasm.base, pt, .unneeded, .fromInterned(ip_index), &wasm.string_bytes, .none);4260 {
4261 var aw: std.Io.Writer.Allocating = .fromArrayList(wasm.base.comp.gpa, &wasm.string_bytes);
4262 defer wasm.string_bytes = aw.toArrayList();
4263 codegen.generateSymbol(&wasm.base, pt, .unneeded, .fromInterned(ip_index), &aw.writer, .none) catch |err| switch (err) {
4264 error.WriteFailed => return error.OutOfMemory,
4265 else => |e| return e,
4266 };
4267 }
42614268
4262 const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);4269 const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start);
4263 const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start);4270 const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start);
src/main.zig+9-5
...@@ -904,7 +904,6 @@ fn buildOutputType(...@@ -904,7 +904,6 @@ fn buildOutputType(
904 var mingw_unicode_entry_point: bool = false;904 var mingw_unicode_entry_point: bool = false;
905 var enable_link_snapshots: bool = false;905 var enable_link_snapshots: bool = false;
906 var debug_compiler_runtime_libs = false;906 var debug_compiler_runtime_libs = false;
907 var opt_incremental: ?bool = null;
908 var install_name: ?[]const u8 = null;907 var install_name: ?[]const u8 = null;
909 var hash_style: link.File.Lld.Elf.HashStyle = .both;908 var hash_style: link.File.Lld.Elf.HashStyle = .both;
910 var entitlements: ?[]const u8 = null;909 var entitlements: ?[]const u8 = null;
...@@ -1374,9 +1373,9 @@ fn buildOutputType(...@@ -1374,9 +1373,9 @@ fn buildOutputType(
1374 }1373 }
1375 } else if (mem.eql(u8, arg, "-fincremental")) {1374 } else if (mem.eql(u8, arg, "-fincremental")) {
1376 dev.check(.incremental);1375 dev.check(.incremental);
1377 opt_incremental = true;1376 create_module.opts.incremental = true;
1378 } else if (mem.eql(u8, arg, "-fno-incremental")) {1377 } else if (mem.eql(u8, arg, "-fno-incremental")) {
1379 opt_incremental = false;1378 create_module.opts.incremental = false;
1380 } else if (mem.eql(u8, arg, "--entitlements")) {1379 } else if (mem.eql(u8, arg, "--entitlements")) {
1381 entitlements = args_iter.nextOrFatal();1380 entitlements = args_iter.nextOrFatal();
1382 } else if (mem.eql(u8, arg, "-fcompiler-rt")) {1381 } else if (mem.eql(u8, arg, "-fcompiler-rt")) {
...@@ -1479,6 +1478,10 @@ fn buildOutputType(...@@ -1479,6 +1478,10 @@ fn buildOutputType(
1479 create_module.opts.use_lld = true;1478 create_module.opts.use_lld = true;
1480 } else if (mem.eql(u8, arg, "-fno-lld")) {1479 } else if (mem.eql(u8, arg, "-fno-lld")) {
1481 create_module.opts.use_lld = false;1480 create_module.opts.use_lld = false;
1481 } else if (mem.eql(u8, arg, "-fnew-linker")) {
1482 create_module.opts.use_new_linker = true;
1483 } else if (mem.eql(u8, arg, "-fno-new-linker")) {
1484 create_module.opts.use_new_linker = false;
1482 } else if (mem.eql(u8, arg, "-fclang")) {1485 } else if (mem.eql(u8, arg, "-fclang")) {
1483 create_module.opts.use_clang = true;1486 create_module.opts.use_clang = true;
1484 } else if (mem.eql(u8, arg, "-fno-clang")) {1487 } else if (mem.eql(u8, arg, "-fno-clang")) {
...@@ -3371,7 +3374,7 @@ fn buildOutputType(...@@ -3371,7 +3374,7 @@ fn buildOutputType(
3371 else => false,3374 else => false,
3372 };3375 };
33733376
3374 const incremental = opt_incremental orelse false;3377 const incremental = create_module.resolved_options.incremental;
3375 if (debug_incremental and !incremental) {3378 if (debug_incremental and !incremental) {
3376 fatal("--debug-incremental requires -fincremental", .{});3379 fatal("--debug-incremental requires -fincremental", .{});
3377 }3380 }
...@@ -3502,7 +3505,6 @@ fn buildOutputType(...@@ -3502,7 +3505,6 @@ fn buildOutputType(
3502 .subsystem = subsystem,3505 .subsystem = subsystem,
3503 .debug_compile_errors = debug_compile_errors,3506 .debug_compile_errors = debug_compile_errors,
3504 .debug_incremental = debug_incremental,3507 .debug_incremental = debug_incremental,
3505 .incremental = incremental,
3506 .enable_link_snapshots = enable_link_snapshots,3508 .enable_link_snapshots = enable_link_snapshots,
3507 .install_name = install_name,3509 .install_name = install_name,
3508 .entitlements = entitlements,3510 .entitlements = entitlements,
...@@ -4016,6 +4018,8 @@ fn createModule(...@@ -4016,6 +4018,8 @@ fn createModule(
4016 error.LldUnavailable => fatal("zig was compiled without LLD libraries", .{}),4018 error.LldUnavailable => fatal("zig was compiled without LLD libraries", .{}),
4017 error.ClangUnavailable => fatal("zig was compiled without Clang libraries", .{}),4019 error.ClangUnavailable => fatal("zig was compiled without Clang libraries", .{}),
4018 error.DllExportFnsRequiresWindows => fatal("only Windows OS targets support DLLs", .{}),4020 error.DllExportFnsRequiresWindows => fatal("only Windows OS targets support DLLs", .{}),
4021 error.NewLinkerIncompatibleObjectFormat => fatal("using the new linker to link {s} files is unsupported", .{@tagName(target.ofmt)}),
4022 error.NewLinkerIncompatibleWithLld => fatal("using the new linker is incompatible with using lld", .{}),
4019 };4023 };
4020 }4024 }
40214025
src/target.zig+7
...@@ -231,6 +231,13 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {...@@ -231,6 +231,13 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
231 };231 };
232}232}
233233
234pub fn hasNewLinkerSupport(ofmt: std.Target.ObjectFormat) bool {
235 return switch (ofmt) {
236 .elf => true,
237 else => false,
238 };
239}
240
234/// The set of targets that our own self-hosted backends have robust support for.241/// The set of targets that our own self-hosted backends have robust support for.
235/// Used to select between LLVM backend and self-hosted backend when compiling in242/// Used to select between LLVM backend and self-hosted backend when compiling in
236/// debug mode. A given target should only return true here if it is passing greater243/// debug mode. A given target should only return true here if it is passing greater
test/incremental/change_exports+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1//#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe3#target=x86_64-windows-cbe
44
test/incremental/change_panic_handler+1
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1#target=x86_64-linux-selfhosted
1#target=x86_64-linux-cbe2#target=x86_64-linux-cbe
2#target=x86_64-windows-cbe3#target=x86_64-windows-cbe
3#update=initial version4#update=initial version
test/incremental/change_panic_handler_explicit+1
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1#target=x86_64-linux-selfhosted
1#target=x86_64-linux-cbe2#target=x86_64-linux-cbe
2#target=x86_64-windows-cbe3#target=x86_64-windows-cbe
3#update=initial version4#update=initial version
test/incremental/change_struct_same_fields+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1//#target=x86_64-linux-selfhosted1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe3#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted4#target=wasm32-wasi-selfhosted
test/incremental/type_becomes_comptime_only+1
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1#target=x86_64-linux-selfhosted
1#target=x86_64-linux-cbe2#target=x86_64-linux-cbe
2#target=x86_64-windows-cbe3#target=x86_64-windows-cbe
3#target=wasm32-wasi-selfhosted4#target=wasm32-wasi-selfhosted