authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-02 22:41:04-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:35-08:00
log16180f525a966de10b6fc0822fea107baf1f24f6
tree86a195c2e0cbfc37016aa1f4a4d42fcd425d687e
parent795e7c64d5f67006246d172e5cd58233cb76f05e

macho linker: conform to explicit error sets

Makes linker functions have small error sets, required to report diagnostics properly rather than having a massive error set that has a lot of codes. Other linker implementations are not ported yet. Also the branch is not passing semantic analysis yet.

16 files changed, 575 insertions(+), 320 deletions(-)

src/Zcu/PerThread.zig+2-2
......@@ -1728,7 +1728,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai
17281728 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
17291729 error.LinkFailure => assert(comp.link_diags.hasErrors()),
17301730 error.Overflow => {
1731 try zcu.failed_codegen.putNoClobber(nav_index, try Zcu.ErrorMsg.create(
1731 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
17321732 gpa,
17331733 zcu.navSrcLoc(nav_index),
17341734 "unable to codegen: {s}",
......@@ -3114,7 +3114,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error
31143114 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
31153115 error.LinkFailure => assert(comp.link_diags.hasErrors()),
31163116 error.Overflow => {
3117 try zcu.failed_codegen.putNoClobber(nav_index, try Zcu.ErrorMsg.create(
3117 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
31183118 gpa,
31193119 zcu.navSrcLoc(nav_index),
31203120 "unable to codegen: {s}",
src/link.zig+1-1
......@@ -745,7 +745,7 @@ pub const File = struct {
745745 }
746746
747747 pub const FlushError = error{
748 /// Indicates an error will be present in `Compilation.link_errors`.
748 /// Indicates an error will be present in `Compilation.link_diags`.
749749 LinkFailure,
750750 OutOfMemory,
751751 };
src/link/Coff.zig+3-6
......@@ -754,7 +754,7 @@ fn allocateGlobal(coff: *Coff) !u32 {
754754 return index;
755755}
756756
757fn addGotEntry(coff: *Coff, target: SymbolWithLoc) !void {
757fn addGotEntry(coff: *Coff, target: SymbolWithLoc) error{ OutOfMemory, LinkFailure }!void {
758758 const gpa = coff.base.comp.gpa;
759759 if (coff.got_table.lookup.contains(target)) return;
760760 const got_index = try coff.got_table.allocateEntry(gpa, target);
......@@ -780,7 +780,7 @@ pub fn createAtom(coff: *Coff) !Atom.Index {
780780 return atom_index;
781781}
782782
783fn growAtom(coff: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 {
783fn growAtom(coff: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) link.File.UpdateNavError!u32 {
784784 const atom = coff.getAtom(atom_index);
785785 const sym = atom.getSymbol(coff);
786786 const align_ok = mem.alignBackward(u32, sym.value, alignment) == sym.value;
......@@ -1313,10 +1313,7 @@ fn updateLazySymbolAtom(
13131313 };
13141314 const code = switch (res) {
13151315 .ok => code_buffer.items,
1316 .fail => |em| {
1317 log.err("{s}", .{em.msg});
1318 return error.CodegenFail;
1319 },
1316 .fail => |em| return diags.fail("failed to generate code: {s}", .{em.msg}),
13201317 };
13211318
13221319 const code_len: u32 = @intCast(code.len);
src/link/Dwarf.zig+6-2
......@@ -23,6 +23,8 @@ debug_str: StringSection,
2323pub const UpdateError = error{
2424 /// Indicates the error is already reported on `failed_codegen` in the Zcu.
2525 CodegenFail,
26 /// Indicates the error is already reported on `link_diags` in the Compilation.
27 LinkFailure,
2628 OutOfMemory,
2729};
2830
......@@ -590,12 +592,14 @@ const Unit = struct {
590592
591593 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
592594 if (unit.off == new_off) return;
593 if (try dwarf.getFile().?.copyRangeAll(
595 const diags = &dwarf.bin_file.base.comp.link_diags;
596 const n = dwarf.getFile().?.copyRangeAll(
594597 sec.off(dwarf) + unit.off,
595598 dwarf.getFile().?,
596599 sec.off(dwarf) + new_off,
597600 unit.len,
598 ) != unit.len) return error.InputOutput;
601 ) catch |err| return diags.fail("failed to copy file range: {s}", .{@errorName(err)});
602 if (n != unit.len) return diags.fail("unexpected short write from copy file range", .{});
599603 unit.off = new_off;
600604 }
601605
src/link/Elf.zig+61-37
......@@ -575,7 +575,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) !?u64 {
575575 }
576576 }
577577
578 if (at_end) try self.base.file.?.setEndPos(end);
578 if (at_end) try self.setEndPos(end);
579579 return null;
580580}
581581
......@@ -638,7 +638,7 @@ pub fn growSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment:
638638
639639 shdr.sh_offset = new_offset;
640640 } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
641 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
641 try self.setEndPos(shdr.sh_offset + needed_size);
642642 }
643643 }
644644
......@@ -960,7 +960,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
960960 },
961961 else => |e| return e,
962962 };
963 try self.base.file.?.pwriteAll(code, file_offset);
963 try self.pwriteAll(code, file_offset);
964964 }
965965
966966 if (has_reloc_errors) return error.LinkFailure;
......@@ -2117,7 +2117,7 @@ pub fn writeShdrTable(self: *Elf) !void {
21172117 mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);
21182118 }
21192119 }
2120 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
2120 try self.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
21212121 },
21222122 .p64 => {
21232123 const buf = try gpa.alloc(elf.Elf64_Shdr, self.sections.items(.shdr).len);
......@@ -2130,7 +2130,7 @@ pub fn writeShdrTable(self: *Elf) !void {
21302130 mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);
21312131 }
21322132 }
2133 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
2133 try self.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
21342134 },
21352135 }
21362136}
......@@ -2157,7 +2157,7 @@ fn writePhdrTable(self: *Elf) !void {
21572157 mem.byteSwapAllFields(elf.Elf32_Phdr, phdr);
21582158 }
21592159 }
2160 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
2160 try self.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
21612161 },
21622162 .p64 => {
21632163 const buf = try gpa.alloc(elf.Elf64_Phdr, self.phdrs.items.len);
......@@ -2169,7 +2169,7 @@ fn writePhdrTable(self: *Elf) !void {
21692169 mem.byteSwapAllFields(elf.Elf64_Phdr, phdr);
21702170 }
21712171 }
2172 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
2172 try self.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
21732173 },
21742174 }
21752175}
......@@ -2319,7 +2319,7 @@ pub fn writeElfHeader(self: *Elf) !void {
23192319
23202320 assert(index == e_ehsize);
23212321
2322 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
2322 try self.pwriteAll(hdr_buf[0..index], 0);
23232323}
23242324
23252325pub fn freeNav(self: *Elf, nav: InternPool.Nav.Index) void {
......@@ -2497,8 +2497,8 @@ pub fn writeMergeSections(self: *Elf) !void {
24972497
24982498 for (self.merge_sections.items) |*msec| {
24992499 const shdr = self.sections.items(.shdr)[msec.output_section_index];
2500 const fileoff = math.cast(usize, msec.value + shdr.sh_offset) orelse return error.Overflow;
2501 const size = math.cast(usize, msec.size) orelse return error.Overflow;
2500 const fileoff = try self.cast(usize, msec.value + shdr.sh_offset);
2501 const size = try self.cast(usize, msec.size);
25022502 try buffer.ensureTotalCapacity(size);
25032503 buffer.appendNTimesAssumeCapacity(0, size);
25042504
......@@ -2506,11 +2506,11 @@ pub fn writeMergeSections(self: *Elf) !void {
25062506 const msub = msec.mergeSubsection(msub_index);
25072507 assert(msub.alive);
25082508 const string = msub.getString(self);
2509 const off = math.cast(usize, msub.value) orelse return error.Overflow;
2509 const off = try self.cast(usize, msub.value);
25102510 @memcpy(buffer.items[off..][0..string.len], string);
25112511 }
25122512
2513 try self.base.file.?.pwriteAll(buffer.items, fileoff);
2513 try self.pwriteAll(buffer.items, fileoff);
25142514 buffer.clearRetainingCapacity();
25152515 }
25162516}
......@@ -3682,7 +3682,7 @@ fn writeAtoms(self: *Elf) !void {
36823682 const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset;
36833683 try th.write(self, buffer.writer());
36843684 assert(buffer.items.len == thunk_size);
3685 try self.base.file.?.pwriteAll(buffer.items, offset);
3685 try self.pwriteAll(buffer.items, offset);
36863686 buffer.clearRetainingCapacity();
36873687 }
36883688 }
......@@ -3790,12 +3790,12 @@ fn writeSyntheticSections(self: *Elf) !void {
37903790 const contents = buffer[0 .. interp.len + 1];
37913791 const shdr = slice.items(.shdr)[shndx];
37923792 assert(shdr.sh_size == contents.len);
3793 try self.base.file.?.pwriteAll(contents, shdr.sh_offset);
3793 try self.pwriteAll(contents, shdr.sh_offset);
37943794 }
37953795
37963796 if (self.section_indexes.hash) |shndx| {
37973797 const shdr = slice.items(.shdr)[shndx];
3798 try self.base.file.?.pwriteAll(self.hash.buffer.items, shdr.sh_offset);
3798 try self.pwriteAll(self.hash.buffer.items, shdr.sh_offset);
37993799 }
38003800
38013801 if (self.section_indexes.gnu_hash) |shndx| {
......@@ -3803,12 +3803,12 @@ fn writeSyntheticSections(self: *Elf) !void {
38033803 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.gnu_hash.size());
38043804 defer buffer.deinit();
38053805 try self.gnu_hash.write(self, buffer.writer());
3806 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
3806 try self.pwriteAll(buffer.items, shdr.sh_offset);
38073807 }
38083808
38093809 if (self.section_indexes.versym) |shndx| {
38103810 const shdr = slice.items(.shdr)[shndx];
3811 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.versym.items), shdr.sh_offset);
3811 try self.pwriteAll(mem.sliceAsBytes(self.versym.items), shdr.sh_offset);
38123812 }
38133813
38143814 if (self.section_indexes.verneed) |shndx| {
......@@ -3816,7 +3816,7 @@ fn writeSyntheticSections(self: *Elf) !void {
38163816 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.verneed.size());
38173817 defer buffer.deinit();
38183818 try self.verneed.write(buffer.writer());
3819 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
3819 try self.pwriteAll(buffer.items, shdr.sh_offset);
38203820 }
38213821
38223822 if (self.section_indexes.dynamic) |shndx| {
......@@ -3824,7 +3824,7 @@ fn writeSyntheticSections(self: *Elf) !void {
38243824 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynamic.size(self));
38253825 defer buffer.deinit();
38263826 try self.dynamic.write(self, buffer.writer());
3827 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
3827 try self.pwriteAll(buffer.items, shdr.sh_offset);
38283828 }
38293829
38303830 if (self.section_indexes.dynsymtab) |shndx| {
......@@ -3832,12 +3832,12 @@ fn writeSyntheticSections(self: *Elf) !void {
38323832 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynsym.size());
38333833 defer buffer.deinit();
38343834 try self.dynsym.write(self, buffer.writer());
3835 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
3835 try self.pwriteAll(buffer.items, shdr.sh_offset);
38363836 }
38373837
38383838 if (self.section_indexes.dynstrtab) |shndx| {
38393839 const shdr = slice.items(.shdr)[shndx];
3840 try self.base.file.?.pwriteAll(self.dynstrtab.items, shdr.sh_offset);
3840 try self.pwriteAll(self.dynstrtab.items, shdr.sh_offset);
38413841 }
38423842
38433843 if (self.section_indexes.eh_frame) |shndx| {
......@@ -3847,21 +3847,21 @@ fn writeSyntheticSections(self: *Elf) !void {
38473847 break :existing_size sym.atom(self).?.size;
38483848 };
38493849 const shdr = slice.items(.shdr)[shndx];
3850 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
3850 const sh_size = try self.cast(usize, shdr.sh_size);
38513851 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
38523852 defer buffer.deinit();
38533853 try eh_frame.writeEhFrame(self, buffer.writer());
38543854 assert(buffer.items.len == sh_size - existing_size);
3855 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset + existing_size);
3855 try self.pwriteAll(buffer.items, shdr.sh_offset + existing_size);
38563856 }
38573857
38583858 if (self.section_indexes.eh_frame_hdr) |shndx| {
38593859 const shdr = slice.items(.shdr)[shndx];
3860 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
3860 const sh_size = try self.cast(usize, shdr.sh_size);
38613861 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
38623862 defer buffer.deinit();
38633863 try eh_frame.writeEhFrameHdr(self, buffer.writer());
3864 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
3864 try self.pwriteAll(buffer.items, shdr.sh_offset);
38653865 }
38663866
38673867 if (self.section_indexes.got) |index| {
......@@ -3869,7 +3869,7 @@ fn writeSyntheticSections(self: *Elf) !void {
38693869 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got.size(self));
38703870 defer buffer.deinit();
38713871 try self.got.write(self, buffer.writer());
3872 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
3872 try self.pwriteAll(buffer.items, shdr.sh_offset);
38733873 }
38743874
38753875 if (self.section_indexes.rela_dyn) |shndx| {
......@@ -3877,7 +3877,7 @@ fn writeSyntheticSections(self: *Elf) !void {
38773877 try self.got.addRela(self);
38783878 try self.copy_rel.addRela(self);
38793879 self.sortRelaDyn();
3880 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);
3880 try self.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);
38813881 }
38823882
38833883 if (self.section_indexes.plt) |shndx| {
......@@ -3885,7 +3885,7 @@ fn writeSyntheticSections(self: *Elf) !void {
38853885 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt.size(self));
38863886 defer buffer.deinit();
38873887 try self.plt.write(self, buffer.writer());
3888 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
3888 try self.pwriteAll(buffer.items, shdr.sh_offset);
38893889 }
38903890
38913891 if (self.section_indexes.got_plt) |shndx| {
......@@ -3893,7 +3893,7 @@ fn writeSyntheticSections(self: *Elf) !void {
38933893 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got_plt.size(self));
38943894 defer buffer.deinit();
38953895 try self.got_plt.write(self, buffer.writer());
3896 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
3896 try self.pwriteAll(buffer.items, shdr.sh_offset);
38973897 }
38983898
38993899 if (self.section_indexes.plt_got) |shndx| {
......@@ -3901,13 +3901,13 @@ fn writeSyntheticSections(self: *Elf) !void {
39013901 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt_got.size(self));
39023902 defer buffer.deinit();
39033903 try self.plt_got.write(self, buffer.writer());
3904 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
3904 try self.pwriteAll(buffer.items, shdr.sh_offset);
39053905 }
39063906
39073907 if (self.section_indexes.rela_plt) |shndx| {
39083908 const shdr = slice.items(.shdr)[shndx];
39093909 try self.plt.addRela(self);
3910 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset);
3910 try self.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset);
39113911 }
39123912
39133913 try self.writeSymtab();
......@@ -3919,7 +3919,7 @@ pub fn writeShStrtab(self: *Elf) !void {
39193919 if (self.section_indexes.shstrtab) |index| {
39203920 const shdr = self.sections.items(.shdr)[index];
39213921 log.debug("writing .shstrtab from 0x{x} to 0x{x}", .{ shdr.sh_offset, shdr.sh_offset + shdr.sh_size });
3922 try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);
3922 try self.pwriteAll(self.shstrtab.items, shdr.sh_offset);
39233923 }
39243924}
39253925
......@@ -3934,7 +3934,7 @@ pub fn writeSymtab(self: *Elf) !void {
39343934 .p32 => @sizeOf(elf.Elf32_Sym),
39353935 .p64 => @sizeOf(elf.Elf64_Sym),
39363936 };
3937 const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow;
3937 const nsyms = try self.cast(usize, @divExact(symtab_shdr.sh_size, sym_size));
39383938
39393939 log.debug("writing {d} symbols in .symtab from 0x{x} to 0x{x}", .{
39403940 nsyms,
......@@ -3947,7 +3947,7 @@ pub fn writeSymtab(self: *Elf) !void {
39473947 });
39483948
39493949 try self.symtab.resize(gpa, nsyms);
3950 const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
3950 const needed_strtab_size = try self.cast(usize, strtab_shdr.sh_size - 1);
39513951 // TODO we could resize instead and in ZigObject/Object always access as slice
39523952 self.strtab.clearRetainingCapacity();
39533953 self.strtab.appendAssumeCapacity(0);
......@@ -4016,17 +4016,17 @@ pub fn writeSymtab(self: *Elf) !void {
40164016 };
40174017 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
40184018 }
4019 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);
4019 try self.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);
40204020 },
40214021 .p64 => {
40224022 if (foreign_endian) {
40234023 for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
40244024 }
4025 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset);
4025 try self.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset);
40264026 },
40274027 }
40284028
4029 try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
4029 try self.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
40304030}
40314031
40324032/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
......@@ -5190,6 +5190,30 @@ pub fn stringTableLookup(strtab: []const u8, off: u32) [:0]const u8 {
51905190 return slice[0..mem.indexOfScalar(u8, slice, 0).? :0];
51915191}
51925192
5193pub fn pwriteAll(elf_file: *Elf, bytes: []const u8, offset: u64) error{LinkFailure}!void {
5194 const comp = elf_file.base.comp;
5195 const diags = &comp.link_diags;
5196 elf_file.base.file.?.pwriteAll(bytes, offset) catch |err| {
5197 return diags.fail("failed to write: {s}", .{@errorName(err)});
5198 };
5199}
5200
5201pub fn setEndPos(elf_file: *Elf, length: u64) error{LinkFailure}!void {
5202 const comp = elf_file.base.comp;
5203 const diags = &comp.link_diags;
5204 elf_file.base.file.?.setEndPos(length) catch |err| {
5205 return diags.fail("failed to set file end pos: {s}", .{@errorName(err)});
5206 };
5207}
5208
5209pub fn cast(elf_file: *Elf, comptime T: type, x: anytype) error{LinkFailure}!T {
5210 return std.math.cast(T, x) orelse {
5211 const comp = elf_file.base.comp;
5212 const diags = &comp.link_diags;
5213 return diags.fail("encountered {d}, overflowing {d}-bit value", .{ x, @bitSizeOf(T) });
5214 };
5215}
5216
51935217const std = @import("std");
51945218const build_options = @import("build_options");
51955219const builtin = @import("builtin");
src/link/MachO.zig+104-44
......@@ -434,7 +434,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
434434 // libc/libSystem dep
435435 self.resolveLibSystem(arena, comp, &system_libs) catch |err| switch (err) {
436436 error.MissingLibSystem => {}, // already reported
437 else => |e| return e, // TODO: convert into an error
437 else => |e| return diags.fail("failed to resolve libSystem: {s}", .{@errorName(e)}),
438438 };
439439
440440 for (comp.link_inputs) |link_input| switch (link_input) {
......@@ -494,7 +494,10 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
494494
495495 try self.resolveSymbols();
496496 try self.convertTentativeDefsAndResolveSpecialSymbols();
497 try self.dedupLiterals();
497 self.dedupLiterals() catch |err| switch (err) {
498 error.LinkFailure => return error.LinkFailure,
499 else => |e| return diags.fail("failed to deduplicate literals: {s}", .{@errorName(e)}),
500 };
498501
499502 if (self.base.gc_sections) {
500503 try dead_strip.gcAtoms(self);
......@@ -551,7 +554,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
551554
552555 try self.writeSectionsToFile();
553556 try self.allocateLinkeditSegment();
554 try self.writeLinkeditSectionsToFile();
557 self.writeLinkeditSectionsToFile() catch |err| switch (err) {
558 error.OutOfMemory => return error.OutOfMemory,
559 error.LinkFailure => return error.LinkFailure,
560 else => |e| return diags.fail("failed to write linkedit sections to file: {s}", .{@errorName(e)}),
561 };
555562
556563 var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: {
557564 // Preallocate space for the code signature.
......@@ -561,7 +568,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
561568 // where the code signature goes into.
562569 var codesig = CodeSignature.init(self.getPageSize());
563570 codesig.code_directory.ident = fs.path.basename(self.base.emit.sub_path);
564 if (self.entitlements) |path| try codesig.addEntitlements(gpa, path);
571 if (self.entitlements) |path| codesig.addEntitlements(gpa, path) catch |err|
572 return diags.fail("failed to add entitlements from {s}: {s}", .{ path, @errorName(err) });
565573 try self.writeCodeSignaturePadding(&codesig);
566574 break :blk codesig;
567575 } else null;
......@@ -573,13 +581,29 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
573581 self.getPageSize(),
574582 );
575583
576 const ncmds, const sizeofcmds, const uuid_cmd_offset = try self.writeLoadCommands();
584 const ncmds, const sizeofcmds, const uuid_cmd_offset = self.writeLoadCommands() catch |err| switch (err) {
585 error.NoSpaceLeft => unreachable,
586 error.OutOfMemory => return error.OutOfMemory,
587 error.LinkFailure => return error.LinkFailure,
588 };
577589 try self.writeHeader(ncmds, sizeofcmds);
578 try self.writeUuid(uuid_cmd_offset, self.requiresCodeSig());
579 if (self.getDebugSymbols()) |dsym| try dsym.flushModule(self);
590 self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) {
591 error.OutOfMemory => return error.OutOfMemory,
592 error.LinkFailure => return error.LinkFailure,
593 else => |e| return diags.fail("failed to calculate and write uuid: {s}", .{@errorName(e)}),
594 };
595 if (self.getDebugSymbols()) |dsym| dsym.flushModule(self) catch |err| switch (err) {
596 error.OutOfMemory => return error.OutOfMemory,
597 else => |e| return diags.fail("failed to get debug symbols: {s}", .{@errorName(e)}),
598 };
580599
600 // Code signing always comes last.
581601 if (codesig) |*csig| {
582 try self.writeCodeSignature(csig); // code signing always comes last
602 self.writeCodeSignature(csig) catch |err| switch (err) {
603 error.OutOfMemory => return error.OutOfMemory,
604 error.LinkFailure => return error.LinkFailure,
605 else => |e| return diags.fail("failed to write code signature: {s}", .{@errorName(e)}),
606 };
583607 const emit = self.base.emit;
584608 try invalidateKernelCache(emit.root_dir.handle, emit.sub_path);
585609 }
......@@ -2171,7 +2195,7 @@ fn allocateSections(self: *MachO) !void {
21712195 fileoff = mem.alignForward(u32, fileoff, page_size);
21722196 }
21732197
2174 const alignment = try math.powi(u32, 2, header.@"align");
2198 const alignment = try self.alignPow(header.@"align");
21752199
21762200 vmaddr = mem.alignForward(u64, vmaddr, alignment);
21772201 header.addr = vmaddr;
......@@ -2327,7 +2351,7 @@ fn allocateLinkeditSegment(self: *MachO) !void {
23272351 seg.vmaddr = mem.alignForward(u64, vmaddr, page_size);
23282352 seg.fileoff = mem.alignForward(u64, fileoff, page_size);
23292353
2330 var off = math.cast(u32, seg.fileoff) orelse return error.Overflow;
2354 var off = try self.cast(u32, seg.fileoff);
23312355 // DYLD_INFO_ONLY
23322356 {
23332357 const cmd = &self.dyld_info_cmd;
......@@ -2392,7 +2416,7 @@ fn resizeSections(self: *MachO) !void {
23922416 if (header.isZerofill()) continue;
23932417 if (self.isZigSection(@intCast(n_sect))) continue; // TODO this is horrible
23942418 const cpu_arch = self.getTarget().cpu.arch;
2395 const size = math.cast(usize, header.size) orelse return error.Overflow;
2419 const size = try self.cast(usize, header.size);
23962420 try out.resize(self.base.comp.gpa, size);
23972421 const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0;
23982422 @memset(out.items, padding_byte);
......@@ -2489,7 +2513,7 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
24892513
24902514 const doWork = struct {
24912515 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
2492 const off = math.cast(usize, th.value) orelse return error.Overflow;
2516 const off = try macho_file.cast(usize, th.value);
24932517 const size = th.size();
24942518 var stream = std.io.fixedBufferStream(buffer[off..][0..size]);
24952519 try th.write(macho_file, stream.writer());
......@@ -2601,7 +2625,7 @@ fn writeSectionsToFile(self: *MachO) !void {
26012625
26022626 const slice = self.sections.slice();
26032627 for (slice.items(.header), slice.items(.out)) |header, out| {
2604 try self.base.file.?.pwriteAll(out.items, header.offset);
2628 try self.pwriteAll(out.items, header.offset);
26052629 }
26062630}
26072631
......@@ -2644,7 +2668,7 @@ fn writeDyldInfo(self: *MachO) !void {
26442668 try self.lazy_bind_section.write(writer);
26452669 try stream.seekTo(cmd.export_off - base_off);
26462670 try self.export_trie.write(writer);
2647 try self.base.file.?.pwriteAll(buffer, cmd.rebase_off);
2671 try self.pwriteAll(buffer, cmd.rebase_off);
26482672}
26492673
26502674pub fn writeDataInCode(self: *MachO) !void {
......@@ -2655,7 +2679,7 @@ pub fn writeDataInCode(self: *MachO) !void {
26552679 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size());
26562680 defer buffer.deinit();
26572681 try self.data_in_code.write(self, buffer.writer());
2658 try self.base.file.?.pwriteAll(buffer.items, cmd.dataoff);
2682 try self.pwriteAll(buffer.items, cmd.dataoff);
26592683}
26602684
26612685fn writeIndsymtab(self: *MachO) !void {
......@@ -2667,15 +2691,15 @@ fn writeIndsymtab(self: *MachO) !void {
26672691 var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size);
26682692 defer buffer.deinit();
26692693 try self.indsymtab.write(self, buffer.writer());
2670 try self.base.file.?.pwriteAll(buffer.items, cmd.indirectsymoff);
2694 try self.pwriteAll(buffer.items, cmd.indirectsymoff);
26712695}
26722696
26732697pub fn writeSymtabToFile(self: *MachO) !void {
26742698 const tracy = trace(@src());
26752699 defer tracy.end();
26762700 const cmd = self.symtab_cmd;
2677 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff);
2678 try self.base.file.?.pwriteAll(self.strtab.items, cmd.stroff);
2701 try self.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff);
2702 try self.pwriteAll(self.strtab.items, cmd.stroff);
26792703}
26802704
26812705fn writeUnwindInfo(self: *MachO) !void {
......@@ -2686,20 +2710,20 @@ fn writeUnwindInfo(self: *MachO) !void {
26862710
26872711 if (self.eh_frame_sect_index) |index| {
26882712 const header = self.sections.items(.header)[index];
2689 const size = math.cast(usize, header.size) orelse return error.Overflow;
2713 const size = try self.cast(usize, header.size);
26902714 const buffer = try gpa.alloc(u8, size);
26912715 defer gpa.free(buffer);
26922716 eh_frame.write(self, buffer);
2693 try self.base.file.?.pwriteAll(buffer, header.offset);
2717 try self.pwriteAll(buffer, header.offset);
26942718 }
26952719
26962720 if (self.unwind_info_sect_index) |index| {
26972721 const header = self.sections.items(.header)[index];
2698 const size = math.cast(usize, header.size) orelse return error.Overflow;
2722 const size = try self.cast(usize, header.size);
26992723 const buffer = try gpa.alloc(u8, size);
27002724 defer gpa.free(buffer);
27012725 try self.unwind_info.write(self, buffer);
2702 try self.base.file.?.pwriteAll(buffer, header.offset);
2726 try self.pwriteAll(buffer, header.offset);
27032727 }
27042728}
27052729
......@@ -2890,7 +2914,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
28902914
28912915 assert(stream.pos == needed_size);
28922916
2893 try self.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
2917 try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
28942918
28952919 return .{ ncmds, buffer.len, uuid_cmd_offset };
28962920}
......@@ -2944,7 +2968,7 @@ fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {
29442968
29452969 log.debug("writing Mach-O header {}", .{header});
29462970
2947 try self.base.file.?.pwriteAll(mem.asBytes(&header), 0);
2971 try self.pwriteAll(mem.asBytes(&header), 0);
29482972}
29492973
29502974fn writeUuid(self: *MachO, uuid_cmd_offset: u64, has_codesig: bool) !void {
......@@ -2954,7 +2978,7 @@ fn writeUuid(self: *MachO, uuid_cmd_offset: u64, has_codesig: bool) !void {
29542978 } else self.codesig_cmd.dataoff;
29552979 try calcUuid(self.base.comp, self.base.file.?, file_size, &self.uuid_cmd.uuid);
29562980 const offset = uuid_cmd_offset + @sizeOf(macho.load_command);
2957 try self.base.file.?.pwriteAll(&self.uuid_cmd.uuid, offset);
2981 try self.pwriteAll(&self.uuid_cmd.uuid, offset);
29582982}
29592983
29602984pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
......@@ -2968,7 +2992,7 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
29682992 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
29692993 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
29702994 // except for code signature data.
2971 try self.base.file.?.pwriteAll(&[_]u8{0}, offset + needed_size - 1);
2995 try self.pwriteAll(&[_]u8{0}, offset + needed_size - 1);
29722996
29732997 self.codesig_cmd.dataoff = @as(u32, @intCast(offset));
29742998 self.codesig_cmd.datasize = @as(u32, @intCast(needed_size));
......@@ -2995,7 +3019,7 @@ pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
29953019 offset + buffer.items.len,
29963020 });
29973021
2998 try self.base.file.?.pwriteAll(buffer.items, offset);
3022 try self.pwriteAll(buffer.items, offset);
29993023}
30003024
30013025pub fn updateFunc(
......@@ -3109,7 +3133,7 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) !?u64 {
31093133 }
31103134 }
31113135
3112 if (at_end) try self.base.file.?.setEndPos(end);
3136 if (at_end) try self.setEndPos(end);
31133137 return null;
31143138}
31153139
......@@ -3193,22 +3217,25 @@ pub fn findFreeSpaceVirtual(self: *MachO, object_size: u64, min_alignment: u32)
31933217 return start;
31943218}
31953219
3196pub fn copyRangeAll(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void {
3220pub fn copyRangeAll(self: *MachO, old_offset: u64, new_offset: u64, size: u64) error{LinkFailure}!void {
3221 const diags = &self.base.comp.link_diags;
31973222 const file = self.base.file.?;
3198 const amt = try file.copyRangeAll(old_offset, file, new_offset, size);
3199 if (amt != size) return error.InputOutput;
3223 const amt = file.copyRangeAll(old_offset, file, new_offset, size) catch |err|
3224 return diags.fail("failed to copy file range: {s}", .{@errorName(err)});
3225 if (amt != size)
3226 return diags.fail("unexpected short write in copy file range", .{});
32003227}
32013228
32023229/// Like File.copyRangeAll but also ensures the source region is zeroed out after copy.
32033230/// This is so that we guarantee zeroed out regions for mapping of zerofill sections by the loader.
3204fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void {
3231fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64) error{ LinkFailure, OutOfMemory }!void {
32053232 const gpa = self.base.comp.gpa;
32063233 try self.copyRangeAll(old_offset, new_offset, size);
3207 const size_u = math.cast(usize, size) orelse return error.Overflow;
3208 const zeroes = try gpa.alloc(u8, size_u);
3234 const size_u = try self.cast(usize, size);
3235 const zeroes = try gpa.alloc(u8, size_u); // TODO no need to allocate here.
32093236 defer gpa.free(zeroes);
32103237 @memset(zeroes, 0);
3211 try self.base.file.?.pwriteAll(zeroes, old_offset);
3238 try self.pwriteAll(zeroes, old_offset);
32123239}
32133240
32143241const InitMetadataOptions = struct {
......@@ -3312,10 +3339,9 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
33123339 const allocSect = struct {
33133340 fn allocSect(macho_file: *MachO, sect_id: u8, size: u64) !void {
33143341 const sect = &macho_file.sections.items(.header)[sect_id];
3315 const alignment = try math.powi(u32, 2, sect.@"align");
3342 const alignment = try macho_file.alignPow(sect.@"align");
33163343 if (!sect.isZerofill()) {
3317 sect.offset = math.cast(u32, try macho_file.findFreeSpace(size, alignment)) orelse
3318 return error.Overflow;
3344 sect.offset = try macho_file.cast(u32, try macho_file.findFreeSpace(size, alignment));
33193345 }
33203346 sect.addr = macho_file.findFreeSpaceVirtual(size, alignment);
33213347 sect.size = size;
......@@ -3397,7 +3423,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
33973423 };
33983424}
33993425
3400pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
3426pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) error{ OutOfMemory, LinkFailure }!void {
34013427 if (self.base.isRelocatable()) {
34023428 try self.growSectionRelocatable(sect_index, needed_size);
34033429 } else {
......@@ -3405,7 +3431,7 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
34053431 }
34063432}
34073433
3408fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void {
3434fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) error{ OutOfMemory, LinkFailure }!void {
34093435 const diags = &self.base.comp.link_diags;
34103436 const sect = &self.sections.items(.header)[sect_index];
34113437
......@@ -3433,7 +3459,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
34333459
34343460 sect.offset = @intCast(new_offset);
34353461 } else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
3436 try self.base.file.?.setEndPos(sect.offset + needed_size);
3462 try self.setEndPos(sect.offset + needed_size);
34373463 }
34383464 seg.filesize = needed_size;
34393465 }
......@@ -3454,7 +3480,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
34543480 seg.vmsize = needed_size;
34553481}
34563482
3457fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void {
3483fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) error{ OutOfMemory, LinkFailure }!void {
34583484 const sect = &self.sections.items(.header)[sect_index];
34593485
34603486 if (!sect.isZerofill()) {
......@@ -3464,7 +3490,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
34643490 sect.size = 0;
34653491
34663492 // Must move the entire section.
3467 const alignment = try math.powi(u32, 2, sect.@"align");
3493 const alignment = try self.alignPow(sect.@"align");
34683494 const new_offset = try self.findFreeSpace(needed_size, alignment);
34693495 const new_addr = self.findFreeSpaceVirtual(needed_size, alignment);
34703496
......@@ -3482,7 +3508,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
34823508 sect.offset = @intCast(new_offset);
34833509 sect.addr = new_addr;
34843510 } else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
3485 try self.base.file.?.setEndPos(sect.offset + needed_size);
3511 try self.setEndPos(sect.offset + needed_size);
34863512 }
34873513 }
34883514 sect.size = needed_size;
......@@ -5316,6 +5342,40 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
53165342 return true;
53175343}
53185344
5345pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void {
5346 const comp = macho_file.base.comp;
5347 const diags = &comp.link_diags;
5348 macho_file.base.file.?.pwriteAll(bytes, offset) catch |err| {
5349 return diags.fail("failed to write: {s}", .{@errorName(err)});
5350 };
5351}
5352
5353pub fn setEndPos(macho_file: *MachO, length: u64) error{LinkFailure}!void {
5354 const comp = macho_file.base.comp;
5355 const diags = &comp.link_diags;
5356 macho_file.base.file.?.setEndPos(length) catch |err| {
5357 return diags.fail("failed to set file end pos: {s}", .{@errorName(err)});
5358 };
5359}
5360
5361pub fn cast(macho_file: *MachO, comptime T: type, x: anytype) error{LinkFailure}!T {
5362 return std.math.cast(T, x) orelse {
5363 const comp = macho_file.base.comp;
5364 const diags = &comp.link_diags;
5365 return diags.fail("encountered {d}, overflowing {d}-bit value", .{ x, @bitSizeOf(T) });
5366 };
5367}
5368
5369pub fn alignPow(macho_file: *MachO, x: u32) error{LinkFailure}!u32 {
5370 const result, const ov = @shlWithOverflow(@as(u32, 1), try cast(macho_file, u5, x));
5371 if (ov != 0) {
5372 const comp = macho_file.base.comp;
5373 const diags = &comp.link_diags;
5374 return diags.fail("alignment overflow", .{});
5375 }
5376 return result;
5377}
5378
53195379/// Branch instruction has 26 bits immediate but is 4 byte aligned.
53205380const jump_bits = @bitSizeOf(i28);
53215381const max_distance = (1 << (jump_bits - 1));
src/link/MachO/Atom.zig+5-5
......@@ -971,7 +971,7 @@ pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 {
971971 }
972972}
973973
974pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.relocation_info) !void {
974pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.relocation_info) error{ LinkFailure, OutOfMemory }!void {
975975 const tracy = trace(@src());
976976 defer tracy.end();
977977
......@@ -983,15 +983,15 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
983983 var i: usize = 0;
984984 for (relocs) |rel| {
985985 defer i += 1;
986 const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;
987 const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow;
986 const rel_offset = try macho_file.cast(usize, rel.offset - self.off);
987 const r_address: i32 = try macho_file.cast(i32, self.value + rel_offset);
988988 assert(r_address >= 0);
989989 const r_symbolnum = r_symbolnum: {
990990 const r_symbolnum: u32 = switch (rel.tag) {
991991 .local => rel.getTargetAtom(self, macho_file).out_n_sect + 1,
992992 .@"extern" => rel.getTargetSymbol(self, macho_file).getOutputSymtabIndex(macho_file).?,
993993 };
994 break :r_symbolnum math.cast(u24, r_symbolnum) orelse return error.Overflow;
994 break :r_symbolnum try macho_file.cast(u24, r_symbolnum);
995995 };
996996 const r_extern = rel.tag == .@"extern";
997997 var addend = rel.addend + rel.getRelocAddend(cpu_arch);
......@@ -1027,7 +1027,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
10271027 } else if (addend > 0) {
10281028 buffer[i] = .{
10291029 .r_address = r_address,
1030 .r_symbolnum = @bitCast(math.cast(i24, addend) orelse return error.Overflow),
1030 .r_symbolnum = @bitCast(try macho_file.cast(i24, addend)),
10311031 .r_pcrel = 0,
10321032 .r_length = 2,
10331033 .r_extern = 0,
src/link/MachO/InternalObject.zig+9-7
......@@ -414,10 +414,11 @@ pub fn resolveLiterals(self: *InternalObject, lp: *MachO.LiteralPool, macho_file
414414 const rel = relocs[0];
415415 assert(rel.tag == .@"extern");
416416 const target = rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?;
417 const target_size = std.math.cast(usize, target.size) orelse return error.Overflow;
417 const target_size = try macho_file.cast(usize, target.size);
418418 try buffer.ensureUnusedCapacity(target_size);
419419 buffer.resize(target_size) catch unreachable;
420 @memcpy(buffer.items, try self.getSectionData(target.n_sect));
420 const section_data = try self.getSectionData(target.n_sect, macho_file);
421 @memcpy(buffer.items, section_data);
421422 const res = try lp.insert(gpa, header.type(), buffer.items);
422423 buffer.clearRetainingCapacity();
423424 if (!res.found_existing) {
......@@ -607,10 +608,11 @@ pub fn writeAtoms(self: *InternalObject, macho_file: *MachO) !void {
607608 if (!atom.isAlive()) continue;
608609 const sect = atom.getInputSection(macho_file);
609610 if (sect.isZerofill()) continue;
610 const off = std.math.cast(usize, atom.value) orelse return error.Overflow;
611 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
611 const off = try macho_file.cast(usize, atom.value);
612 const size = try macho_file.cast(usize, atom.size);
612613 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items[off..][0..size];
613 @memcpy(buffer, try self.getSectionData(atom.n_sect));
614 const section_data = try self.getSectionData(atom.n_sect, macho_file);
615 @memcpy(buffer, section_data);
614616 try atom.resolveRelocs(macho_file, buffer);
615617 }
616618}
......@@ -644,13 +646,13 @@ fn addSection(self: *InternalObject, allocator: Allocator, segname: []const u8,
644646 return n_sect;
645647}
646648
647fn getSectionData(self: *const InternalObject, index: u32) error{Overflow}![]const u8 {
649fn getSectionData(self: *const InternalObject, index: u32, macho_file: *MachO) error{LinkFailure}![]const u8 {
648650 const slice = self.sections.slice();
649651 assert(index < slice.items(.header).len);
650652 const sect = slice.items(.header)[index];
651653 const extra = slice.items(.extra)[index];
652654 if (extra.is_objc_methname) {
653 const size = std.math.cast(usize, sect.size) orelse return error.Overflow;
655 const size = try macho_file.cast(usize, sect.size);
654656 return self.objc_methnames.items[sect.offset..][0..size];
655657 } else if (extra.is_objc_selref)
656658 return &self.objc_selrefs
src/link/MachO/Object.zig+32-34
......@@ -582,7 +582,7 @@ fn initPointerLiterals(self: *Object, allocator: Allocator, macho_file: *MachO)
582582 );
583583 return error.MalformedObject;
584584 }
585 const num_ptrs = math.cast(usize, @divExact(sect.size, rec_size)) orelse return error.Overflow;
585 const num_ptrs = try macho_file.cast(usize, @divExact(sect.size, rec_size));
586586
587587 for (0..num_ptrs) |i| {
588588 const pos: u32 = @as(u32, @intCast(i)) * rec_size;
......@@ -650,8 +650,8 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
650650
651651 for (subs.items) |sub| {
652652 const atom = self.getAtom(sub.atom).?;
653 const atom_off = math.cast(usize, atom.off) orelse return error.Overflow;
654 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
653 const atom_off = try macho_file.cast(usize, atom.off);
654 const atom_size = try macho_file.cast(usize, atom.size);
655655 const atom_data = data[atom_off..][0..atom_size];
656656 const res = try lp.insert(gpa, header.type(), atom_data);
657657 if (!res.found_existing) {
......@@ -674,8 +674,8 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
674674 .local => rel.getTargetAtom(atom.*, macho_file),
675675 .@"extern" => rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?,
676676 };
677 const addend = math.cast(u32, rel.addend) orelse return error.Overflow;
678 const target_size = math.cast(usize, target.size) orelse return error.Overflow;
677 const addend = try macho_file.cast(u32, rel.addend);
678 const target_size = try macho_file.cast(usize, target.size);
679679 try buffer.ensureUnusedCapacity(target_size);
680680 buffer.resize(target_size) catch unreachable;
681681 const gop = try sections_data.getOrPut(target.n_sect);
......@@ -683,7 +683,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
683683 gop.value_ptr.* = try self.readSectionData(gpa, file, @intCast(target.n_sect));
684684 }
685685 const data = gop.value_ptr.*;
686 const target_off = math.cast(usize, target.off) orelse return error.Overflow;
686 const target_off = try macho_file.cast(usize, target.off);
687687 @memcpy(buffer.items, data[target_off..][0..target_size]);
688688 const res = try lp.insert(gpa, header.type(), buffer.items[addend..]);
689689 buffer.clearRetainingCapacity();
......@@ -1033,7 +1033,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi
10331033 const sect = slice.items(.header)[sect_id];
10341034 const relocs = slice.items(.relocs)[sect_id];
10351035
1036 const size = math.cast(usize, sect.size) orelse return error.Overflow;
1036 const size = try macho_file.cast(usize, sect.size);
10371037 try self.eh_frame_data.resize(allocator, size);
10381038 const amt = try file.preadAll(self.eh_frame_data.items, sect.offset + self.offset);
10391039 if (amt != self.eh_frame_data.items.len) return error.InputOutput;
......@@ -1696,7 +1696,7 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
16961696
16971697pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
16981698 // Header
1699 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
1699 const size = try macho_file.cast(usize, self.output_ar_state.size);
17001700 const basename = std.fs.path.basename(self.path.sub_path);
17011701 try Archive.writeHeader(basename, size, ar_format, writer);
17021702 // Data
......@@ -1826,7 +1826,7 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void {
18261826
18271827 for (headers, 0..) |header, n_sect| {
18281828 if (header.isZerofill()) continue;
1829 const size = math.cast(usize, header.size) orelse return error.Overflow;
1829 const size = try macho_file.cast(usize, header.size);
18301830 const data = try gpa.alloc(u8, size);
18311831 const amt = try file.preadAll(data, header.offset + self.offset);
18321832 if (amt != data.len) return error.InputOutput;
......@@ -1837,9 +1837,9 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void {
18371837 if (!atom.isAlive()) continue;
18381838 const sect = atom.getInputSection(macho_file);
18391839 if (sect.isZerofill()) continue;
1840 const value = math.cast(usize, atom.value) orelse return error.Overflow;
1841 const off = math.cast(usize, atom.off) orelse return error.Overflow;
1842 const size = math.cast(usize, atom.size) orelse return error.Overflow;
1840 const value = try macho_file.cast(usize, atom.value);
1841 const off = try macho_file.cast(usize, atom.off);
1842 const size = try macho_file.cast(usize, atom.size);
18431843 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;
18441844 const data = sections_data[atom.n_sect];
18451845 @memcpy(buffer[value..][0..size], data[off..][0..size]);
......@@ -1865,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
18651865
18661866 for (headers, 0..) |header, n_sect| {
18671867 if (header.isZerofill()) continue;
1868 const size = math.cast(usize, header.size) orelse return error.Overflow;
1868 const size = try macho_file.cast(usize, header.size);
18691869 const data = try gpa.alloc(u8, size);
18701870 const amt = try file.preadAll(data, header.offset + self.offset);
18711871 if (amt != data.len) return error.InputOutput;
......@@ -1876,9 +1876,9 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
18761876 if (!atom.isAlive()) continue;
18771877 const sect = atom.getInputSection(macho_file);
18781878 if (sect.isZerofill()) continue;
1879 const value = math.cast(usize, atom.value) orelse return error.Overflow;
1880 const off = math.cast(usize, atom.off) orelse return error.Overflow;
1881 const size = math.cast(usize, atom.size) orelse return error.Overflow;
1879 const value = try macho_file.cast(usize, atom.value);
1880 const off = try macho_file.cast(usize, atom.off);
1881 const size = try macho_file.cast(usize, atom.size);
18821882 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;
18831883 const data = sections_data[atom.n_sect];
18841884 @memcpy(buffer[value..][0..size], data[off..][0..size]);
......@@ -1909,29 +1909,27 @@ pub fn calcCompactUnwindSizeRelocatable(self: *Object, macho_file: *MachO) void
19091909 }
19101910}
19111911
1912fn addReloc(offset: u32, arch: std.Target.Cpu.Arch) !macho.relocation_info {
1913 return .{
1914 .r_address = std.math.cast(i32, offset) orelse return error.Overflow,
1915 .r_symbolnum = 0,
1916 .r_pcrel = 0,
1917 .r_length = 3,
1918 .r_extern = 0,
1919 .r_type = switch (arch) {
1920 .aarch64 => @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
1921 .x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
1922 else => unreachable,
1923 },
1924 };
1925}
1926
19121927pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {
19131928 const tracy = trace(@src());
19141929 defer tracy.end();
19151930
19161931 const cpu_arch = macho_file.getTarget().cpu.arch;
19171932
1918 const addReloc = struct {
1919 fn addReloc(offset: u32, arch: std.Target.Cpu.Arch) !macho.relocation_info {
1920 return .{
1921 .r_address = math.cast(i32, offset) orelse return error.Overflow,
1922 .r_symbolnum = 0,
1923 .r_pcrel = 0,
1924 .r_length = 3,
1925 .r_extern = 0,
1926 .r_type = switch (arch) {
1927 .aarch64 => @intFromEnum(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
1928 .x86_64 => @intFromEnum(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
1929 else => unreachable,
1930 },
1931 };
1932 }
1933 }.addReloc;
1934
19351933 const nsect = macho_file.unwind_info_sect_index.?;
19361934 const buffer = macho_file.sections.items(.out)[nsect].items;
19371935 const relocs = macho_file.sections.items(.relocs)[nsect].items;
......@@ -1967,7 +1965,7 @@ pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {
19671965
19681966 // Personality function
19691967 if (rec.getPersonality(macho_file)) |sym| {
1970 const r_symbolnum = math.cast(u24, sym.getOutputSymtabIndex(macho_file).?) orelse return error.Overflow;
1968 const r_symbolnum = try macho_file.cast(u24, sym.getOutputSymtabIndex(macho_file).?);
19711969 var reloc = try addReloc(offset + 16, cpu_arch);
19721970 reloc.r_symbolnum = r_symbolnum;
19731971 reloc.r_extern = 1;
src/link/MachO/ZigObject.zig+45-37
......@@ -290,12 +290,15 @@ pub fn dedupLiterals(self: *ZigObject, lp: MachO.LiteralPool, macho_file: *MachO
290290/// We need this so that we can write to an archive.
291291/// TODO implement writing ZigObject data directly to a buffer instead.
292292pub fn readFileContents(self: *ZigObject, macho_file: *MachO) !void {
293 const diags = &macho_file.base.comp.link_diags;
293294 // Size of the output object file is always the offset + size of the strtab
294295 const size = macho_file.symtab_cmd.stroff + macho_file.symtab_cmd.strsize;
295296 const gpa = macho_file.base.comp.gpa;
296297 try self.data.resize(gpa, size);
297 const amt = try macho_file.base.file.?.preadAll(self.data.items, 0);
298 if (amt != size) return error.InputOutput;
298 const amt = macho_file.base.file.?.preadAll(self.data.items, 0) catch |err|
299 return diags.fail("failed to read output file: {s}", .{@errorName(err)});
300 if (amt != size)
301 return diags.fail("unexpected EOF reading from output file", .{});
299302}
300303
301304pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, macho_file: *MachO) error{OutOfMemory}!void {
......@@ -376,7 +379,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {
376379 if (atom.getRelocs(macho_file).len == 0) continue;
377380 // TODO: we will resolve and write ZigObject's TLS data twice:
378381 // once here, and once in writeAtoms
379 const atom_size = std.math.cast(usize, atom.size) orelse return error.Overflow;
382 const atom_size = try macho_file.cast(usize, atom.size);
380383 const code = try gpa.alloc(u8, atom_size);
381384 defer gpa.free(code);
382385 self.getAtomData(macho_file, atom.*, code) catch |err| {
......@@ -400,7 +403,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {
400403 has_error = true;
401404 continue;
402405 };
403 try macho_file.base.file.?.pwriteAll(code, file_offset);
406 try macho_file.pwriteAll(code, file_offset);
404407 }
405408
406409 if (has_error) return error.ResolveFailed;
......@@ -419,7 +422,7 @@ pub fn calcNumRelocs(self: *ZigObject, macho_file: *MachO) void {
419422 }
420423}
421424
422pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void {
425pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) error{ LinkFailure, OutOfMemory }!void {
423426 const gpa = macho_file.base.comp.gpa;
424427 const diags = &macho_file.base.comp.link_diags;
425428
......@@ -432,14 +435,14 @@ pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void {
432435 if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue;
433436 if (atom.getRelocs(macho_file).len == 0) continue;
434437 const extra = atom.getExtra(macho_file);
435 const atom_size = std.math.cast(usize, atom.size) orelse return error.Overflow;
438 const atom_size = try macho_file.cast(usize, atom.size);
436439 const code = try gpa.alloc(u8, atom_size);
437440 defer gpa.free(code);
438441 self.getAtomData(macho_file, atom.*, code) catch |err|
439442 return diags.fail("failed to fetch code for '{s}': {s}", .{ atom.getName(macho_file), @errorName(err) });
440443 const file_offset = header.offset + atom.value;
441444 try atom.writeRelocs(macho_file, code, relocs[extra.rel_out_index..][0..extra.rel_out_count]);
442 try macho_file.base.file.?.pwriteAll(code, file_offset);
445 try macho_file.pwriteAll(code, file_offset);
443446 }
444447}
445448
......@@ -457,8 +460,8 @@ pub fn writeAtomsRelocatable(self: *ZigObject, macho_file: *MachO) !void {
457460 if (sect.isZerofill()) continue;
458461 if (macho_file.isZigSection(atom.out_n_sect)) continue;
459462 if (atom.getRelocs(macho_file).len == 0) continue;
460 const off = std.math.cast(usize, atom.value) orelse return error.Overflow;
461 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
463 const off = try macho_file.cast(usize, atom.value);
464 const size = try macho_file.cast(usize, atom.size);
462465 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;
463466 try self.getAtomData(macho_file, atom.*, buffer[off..][0..size]);
464467 const relocs = macho_file.sections.items(.relocs)[atom.out_n_sect].items;
......@@ -480,8 +483,8 @@ pub fn writeAtoms(self: *ZigObject, macho_file: *MachO) !void {
480483 const sect = atom.getInputSection(macho_file);
481484 if (sect.isZerofill()) continue;
482485 if (macho_file.isZigSection(atom.out_n_sect)) continue;
483 const off = std.math.cast(usize, atom.value) orelse return error.Overflow;
484 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
486 const off = try macho_file.cast(usize, atom.value);
487 const size = try macho_file.cast(usize, atom.size);
485488 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;
486489 try self.getAtomData(macho_file, atom.*, buffer[off..][0..size]);
487490 try atom.resolveRelocs(macho_file, buffer[off..][0..size]);
......@@ -546,7 +549,9 @@ pub fn getInputSection(self: ZigObject, atom: Atom, macho_file: *MachO) macho.se
546549 return sect;
547550}
548551
549pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) !void {
552pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) link.File.FlushError!void {
553 const diags = &macho_file.base.comp.link_diags;
554
550555 // Handle any lazy symbols that were emitted by incremental compilation.
551556 if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
552557 const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid);
......@@ -554,24 +559,18 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
554559
555560 // Most lazy symbols can be updated on first use, but
556561 // anyerror needs to wait for everything to be flushed.
557 if (metadata.text_state != .unused) self.updateLazySymbol(
562 if (metadata.text_state != .unused) try self.updateLazySymbol(
558563 macho_file,
559564 pt,
560565 .{ .kind = .code, .ty = .anyerror_type },
561566 metadata.text_symbol_index,
562 ) catch |err| return switch (err) {
563 error.CodegenFail => error.LinkFailure,
564 else => |e| e,
565 };
566 if (metadata.const_state != .unused) self.updateLazySymbol(
567 );
568 if (metadata.const_state != .unused) try self.updateLazySymbol(
567569 macho_file,
568570 pt,
569571 .{ .kind = .const_data, .ty = .anyerror_type },
570572 metadata.const_symbol_index,
571 ) catch |err| return switch (err) {
572 error.CodegenFail => error.LinkFailure,
573 else => |e| e,
574 };
573 );
575574 }
576575 for (self.lazy_syms.values()) |*metadata| {
577576 if (metadata.text_state != .unused) metadata.text_state = .flushed;
......@@ -581,7 +580,11 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
581580 if (self.dwarf) |*dwarf| {
582581 const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid);
583582 defer pt.deactivate();
584 try dwarf.flushModule(pt);
583 dwarf.flushModule(pt) catch |err| switch (err) {
584 error.OutOfMemory => return error.OutOfMemory,
585 error.CodegenFail => return error.LinkFailure,
586 else => |e| return diags.fail("failed to flush dwarf module: {s}", .{@errorName(e)}),
587 };
585588
586589 self.debug_abbrev_dirty = false;
587590 self.debug_aranges_dirty = false;
......@@ -616,6 +619,7 @@ pub fn getNavVAddr(
616619 const sym = self.symbols.items[sym_index];
617620 const vaddr = sym.getAddress(.{}, macho_file);
618621 switch (reloc_info.parent) {
622 .none => unreachable,
619623 .atom_index => |atom_index| {
620624 const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?;
621625 try parent_atom.addReloc(macho_file, .{
......@@ -655,6 +659,7 @@ pub fn getUavVAddr(
655659 const sym = self.symbols.items[sym_index];
656660 const vaddr = sym.getAddress(.{}, macho_file);
657661 switch (reloc_info.parent) {
662 .none => unreachable,
658663 .atom_index => |atom_index| {
659664 const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?;
660665 try parent_atom.addReloc(macho_file, .{
......@@ -766,7 +771,7 @@ pub fn updateFunc(
766771 func_index: InternPool.Index,
767772 air: Air,
768773 liveness: Liveness,
769) !void {
774) link.File.UpdateNavError!void {
770775 const tracy = trace(@src());
771776 defer tracy.end();
772777
......@@ -936,7 +941,7 @@ fn updateNavCode(
936941 sym_index: Symbol.Index,
937942 sect_index: u8,
938943 code: []const u8,
939) !void {
944) link.File.UpdateNavError!void {
940945 const zcu = pt.zcu;
941946 const gpa = zcu.gpa;
942947 const ip = &zcu.intern_pool;
......@@ -950,6 +955,7 @@ fn updateNavCode(
950955 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
951956 };
952957
958 const diags = &macho_file.base.comp.link_diags;
953959 const sect = &macho_file.sections.items(.header)[sect_index];
954960 const sym = &self.symbols.items[sym_index];
955961 const nlist = &self.symtab.items(.nlist)[sym.nlist_idx];
......@@ -978,7 +984,7 @@ fn updateNavCode(
978984 const need_realloc = code.len > capacity or !required_alignment.check(atom.value);
979985
980986 if (need_realloc) {
981 try atom.grow(macho_file);
987 atom.grow(macho_file) catch |err| return diags.fail("failed to grow atom: {s}", .{@errorName(err)});
982988 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value });
983989 if (old_vaddr != atom.value) {
984990 sym.value = 0;
......@@ -1000,7 +1006,7 @@ fn updateNavCode(
10001006
10011007 if (!sect.isZerofill()) {
10021008 const file_offset = sect.offset + atom.value;
1003 try macho_file.base.file.?.pwriteAll(code, file_offset);
1009 try macho_file.pwriteAll(code, file_offset);
10041010 }
10051011}
10061012
......@@ -1236,7 +1242,7 @@ fn lowerConst(
12361242
12371243 const sect = macho_file.sections.items(.header)[output_section_index];
12381244 const file_offset = sect.offset + atom.value;
1239 try macho_file.base.file.?.pwriteAll(code, file_offset);
1245 try macho_file.pwriteAll(code, file_offset);
12401246
12411247 return .{ .ok = sym_index };
12421248}
......@@ -1347,9 +1353,10 @@ fn updateLazySymbol(
13471353 pt: Zcu.PerThread,
13481354 lazy_sym: link.File.LazySymbol,
13491355 symbol_index: Symbol.Index,
1350) !void {
1356) error{ OutOfMemory, LinkFailure }!void {
13511357 const zcu = pt.zcu;
13521358 const gpa = zcu.gpa;
1359 const diags = &macho_file.base.comp.link_diags;
13531360
13541361 var required_alignment: Atom.Alignment = .none;
13551362 var code_buffer = std.ArrayList(u8).init(gpa);
......@@ -1365,7 +1372,7 @@ fn updateLazySymbol(
13651372 };
13661373
13671374 const src = Type.fromInterned(lazy_sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded;
1368 const res = try codegen.generateLazySymbol(
1375 const res = codegen.generateLazySymbol(
13691376 &macho_file.base,
13701377 pt,
13711378 src,
......@@ -1374,13 +1381,14 @@ fn updateLazySymbol(
13741381 &code_buffer,
13751382 .none,
13761383 .{ .atom_index = symbol_index },
1377 );
1384 ) catch |err| switch (err) {
1385 error.CodegenFail => return error.LinkFailure,
1386 error.OutOfMemory => return error.OutOfMemory,
1387 else => |e| return diags.fail("failed to codegen symbol: {s}", .{@errorName(e)}),
1388 };
13781389 const code = switch (res) {
13791390 .ok => code_buffer.items,
1380 .fail => |em| {
1381 log.err("{s}", .{em.msg});
1382 return error.CodegenFail;
1383 },
1391 .fail => |em| return diags.fail("codegen failure: {s}", .{em.msg}),
13841392 };
13851393
13861394 const output_section_index = switch (lazy_sym.kind) {
......@@ -1412,7 +1420,7 @@ fn updateLazySymbol(
14121420
14131421 const sect = macho_file.sections.items(.header)[output_section_index];
14141422 const file_offset = sect.offset + atom.value;
1415 try macho_file.base.file.?.pwriteAll(code, file_offset);
1423 try macho_file.pwriteAll(code, file_offset);
14161424}
14171425
14181426pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
......@@ -1486,7 +1494,7 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, macho_file: *MachO) !void {
14861494 .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf),
14871495 else => @panic("TODO implement write trampoline for this CPU arch"),
14881496 };
1489 try macho_file.base.file.?.pwriteAll(out, fileoff);
1497 try macho_file.pwriteAll(out, fileoff);
14901498}
14911499
14921500pub fn getOrCreateMetadataForNav(
src/link/MachO/relocatable.zig+59-36
......@@ -18,13 +18,15 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
1818 // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all
1919 // debug info segments/sections (this is apparently by design by Apple), we copy
2020 // the *only* input file over.
21 // TODO: in the future, when we implement `dsymutil` alternative directly in the Zig
22 // compiler, investigate if we can get rid of this `if` prong here.
2321 const path = positionals.items[0].path().?;
24 const in_file = try path.root_dir.handle.openFile(path.sub_path, .{});
25 const stat = try in_file.stat();
26 const amt = try in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size);
27 if (amt != stat.size) return error.InputOutput; // TODO: report an actual user error
22 const in_file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err|
23 return diags.fail("failed to open {}: {s}", .{ path, @errorName(err) });
24 const stat = in_file.stat() catch |err|
25 return diags.fail("failed to stat {}: {s}", .{ path, @errorName(err) });
26 const amt = in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size) catch |err|
27 return diags.fail("failed to copy range of file {}: {s}", .{ path, @errorName(err) });
28 if (amt != stat.size)
29 return diags.fail("unexpected short write in copy range of file {}", .{path});
2830 return;
2931 }
3032
......@@ -40,7 +42,11 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
4042 if (diags.hasErrors()) return error.LinkFailure;
4143
4244 try macho_file.resolveSymbols();
43 try macho_file.dedupLiterals();
45 macho_file.dedupLiterals() catch |err| switch (err) {
46 error.OutOfMemory => return error.OutOfMemory,
47 error.LinkFailure => return error.LinkFailure,
48 else => |e| return diags.fail("failed to update ar size: {s}", .{@errorName(e)}),
49 };
4450 markExports(macho_file);
4551 claimUnresolved(macho_file);
4652 try initOutputSections(macho_file);
......@@ -108,7 +114,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
108114 try macho_file.addAtomsToSections();
109115 try calcSectionSizes(macho_file);
110116 try createSegment(macho_file);
111 try allocateSections(macho_file);
117 allocateSections(macho_file) catch |err|
118 return diags.fail("failed to allocate sections: {s}", .{@errorName(err)});
112119 allocateSegment(macho_file);
113120
114121 if (build_options.enable_logging) {
......@@ -126,8 +133,6 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
126133 const ncmds, const sizeofcmds = try writeLoadCommands(macho_file);
127134 try writeHeader(macho_file, ncmds, sizeofcmds);
128135
129 // TODO we can avoid reading in the file contents we just wrote if we give the linker
130 // ability to write directly to a buffer.
131136 try zo.readFileContents(macho_file);
132137 }
133138
......@@ -152,7 +157,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
152157
153158 // Update sizes of contributing objects
154159 for (files.items) |index| {
155 try macho_file.getFile(index).?.updateArSize(macho_file);
160 macho_file.getFile(index).?.updateArSize(macho_file) catch |err|
161 return diags.fail("failed to update ar size: {s}", .{@errorName(err)});
156162 }
157163
158164 // Update file offsets of contributing objects
......@@ -171,7 +177,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
171177 state.file_off = pos;
172178 pos += @sizeOf(Archive.ar_hdr);
173179 pos += mem.alignForward(usize, zo.basename.len + 1, ptr_width);
174 pos += math.cast(usize, state.size) orelse return error.Overflow;
180 pos += try macho_file.cast(usize, state.size);
175181 },
176182 .object => |o| {
177183 const state = &o.output_ar_state;
......@@ -179,7 +185,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
179185 state.file_off = pos;
180186 pos += @sizeOf(Archive.ar_hdr);
181187 pos += mem.alignForward(usize, o.path.basename().len + 1, ptr_width);
182 pos += math.cast(usize, state.size) orelse return error.Overflow;
188 pos += try macho_file.cast(usize, state.size);
183189 },
184190 else => unreachable,
185191 }
......@@ -201,7 +207,10 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
201207 try writer.writeAll(Archive.ARMAG);
202208
203209 // Write symtab
204 try ar_symtab.write(format, macho_file, writer);
210 ar_symtab.write(format, macho_file, writer) catch |err| switch (err) {
211 error.OutOfMemory => return error.OutOfMemory,
212 else => |e| return diags.fail("failed to write archive symbol table: {s}", .{@errorName(e)}),
213 };
205214
206215 // Write object files
207216 for (files.items) |index| {
......@@ -210,13 +219,14 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
210219 if (padding > 0) {
211220 try writer.writeByteNTimes(0, padding);
212221 }
213 try macho_file.getFile(index).?.writeAr(format, macho_file, writer);
222 macho_file.getFile(index).?.writeAr(format, macho_file, writer) catch |err|
223 return diags.fail("failed to write archive: {s}", .{@errorName(err)});
214224 }
215225
216226 assert(buffer.items.len == total_size);
217227
218 try macho_file.base.file.?.setEndPos(total_size);
219 try macho_file.base.file.?.pwriteAll(buffer.items, 0);
228 try macho_file.setEndPos(total_size);
229 try macho_file.pwriteAll(buffer.items, 0);
220230
221231 if (diags.hasErrors()) return error.LinkFailure;
222232}
......@@ -452,11 +462,10 @@ fn allocateSections(macho_file: *MachO) !void {
452462 for (slice.items(.header)) |*header| {
453463 const needed_size = header.size;
454464 header.size = 0;
455 const alignment = try math.powi(u32, 2, header.@"align");
465 const alignment = try macho_file.alignPow(header.@"align");
456466 if (!header.isZerofill()) {
457467 if (needed_size > macho_file.allocatedSize(header.offset)) {
458 header.offset = math.cast(u32, try macho_file.findFreeSpace(needed_size, alignment)) orelse
459 return error.Overflow;
468 header.offset = try macho_file.cast(u32, try macho_file.findFreeSpace(needed_size, alignment));
460469 }
461470 }
462471 if (needed_size > macho_file.allocatedSizeVirtual(header.addr)) {
......@@ -572,7 +581,7 @@ fn sortRelocs(macho_file: *MachO) void {
572581 }
573582}
574583
575fn writeSections(macho_file: *MachO) !void {
584fn writeSections(macho_file: *MachO) link.File.FlushError!void {
576585 const tracy = trace(@src());
577586 defer tracy.end();
578587
......@@ -583,7 +592,7 @@ fn writeSections(macho_file: *MachO) !void {
583592 for (slice.items(.header), slice.items(.out), slice.items(.relocs), 0..) |header, *out, *relocs, n_sect| {
584593 if (header.isZerofill()) continue;
585594 if (!macho_file.isZigSection(@intCast(n_sect))) { // TODO this is wrong; what about debug sections?
586 const size = math.cast(usize, header.size) orelse return error.Overflow;
595 const size = try macho_file.cast(usize, header.size);
587596 try out.resize(gpa, size);
588597 const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0;
589598 @memset(out.items, padding_byte);
......@@ -662,16 +671,16 @@ fn writeSectionsToFile(macho_file: *MachO) !void {
662671
663672 const slice = macho_file.sections.slice();
664673 for (slice.items(.header), slice.items(.out), slice.items(.relocs)) |header, out, relocs| {
665 try macho_file.base.file.?.pwriteAll(out.items, header.offset);
666 try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
674 try macho_file.pwriteAll(out.items, header.offset);
675 try macho_file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
667676 }
668677
669678 try macho_file.writeDataInCode();
670 try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff);
671 try macho_file.base.file.?.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff);
679 try macho_file.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff);
680 try macho_file.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff);
672681}
673682
674fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {
683fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } {
675684 const gpa = macho_file.base.comp.gpa;
676685 const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file);
677686 const buffer = try gpa.alloc(u8, needed_size);
......@@ -686,31 +695,45 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {
686695 {
687696 assert(macho_file.segments.items.len == 1);
688697 const seg = macho_file.segments.items[0];
689 try writer.writeStruct(seg);
698 writer.writeStruct(seg) catch |err| switch (err) {
699 error.NoSpaceLeft => unreachable,
700 };
690701 for (macho_file.sections.items(.header)) |header| {
691 try writer.writeStruct(header);
702 writer.writeStruct(header) catch |err| switch (err) {
703 error.NoSpaceLeft => unreachable,
704 };
692705 }
693706 ncmds += 1;
694707 }
695708
696 try writer.writeStruct(macho_file.data_in_code_cmd);
709 writer.writeStruct(macho_file.data_in_code_cmd) catch |err| switch (err) {
710 error.NoSpaceLeft => unreachable,
711 };
697712 ncmds += 1;
698 try writer.writeStruct(macho_file.symtab_cmd);
713 writer.writeStruct(macho_file.symtab_cmd) catch |err| switch (err) {
714 error.NoSpaceLeft => unreachable,
715 };
699716 ncmds += 1;
700 try writer.writeStruct(macho_file.dysymtab_cmd);
717 writer.writeStruct(macho_file.dysymtab_cmd) catch |err| switch (err) {
718 error.NoSpaceLeft => unreachable,
719 };
701720 ncmds += 1;
702721
703722 if (macho_file.platform.isBuildVersionCompatible()) {
704 try load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer);
723 load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
724 error.NoSpaceLeft => unreachable,
725 };
705726 ncmds += 1;
706727 } else {
707 try load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer);
728 load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
729 error.NoSpaceLeft => unreachable,
730 };
708731 ncmds += 1;
709732 }
710733
711734 assert(stream.pos == needed_size);
712735
713 try macho_file.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
736 try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
714737
715738 return .{ ncmds, buffer.len };
716739}
......@@ -742,7 +765,7 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
742765 header.ncmds = @intCast(ncmds);
743766 header.sizeofcmds = @intCast(sizeofcmds);
744767
745 try macho_file.base.file.?.pwriteAll(mem.asBytes(&header), 0);
768 try macho_file.pwriteAll(mem.asBytes(&header), 0);
746769}
747770
748771const std = @import("std");
src/link/Plan9.zig+38-25
......@@ -535,16 +535,21 @@ fn allocateGotIndex(self: *Plan9) usize {
535535 }
536536}
537537
538pub fn flush(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
538pub fn flush(
539 self: *Plan9,
540 arena: Allocator,
541 tid: Zcu.PerThread.Id,
542 prog_node: std.Progress.Node,
543) link.File.FlushError!void {
539544 const comp = self.base.comp;
545 const diags = &comp.link_diags;
540546 const use_lld = build_options.have_llvm and comp.config.use_lld;
541547 assert(!use_lld);
542548
543549 switch (link.File.effectiveOutputMode(use_lld, comp.config.output_mode)) {
544550 .Exe => {},
545 // plan9 object files are totally different
546 .Obj => return error.TODOImplementPlan9Objs,
547 .Lib => return error.TODOImplementWritingLibFiles,
551 .Obj => return diags.fail("writing plan9 object files unimplemented", .{}),
552 .Lib => return diags.fail("writing plan9 lib files unimplemented", .{}),
548553 }
549554 return self.flushModule(arena, tid, prog_node);
550555}
......@@ -589,7 +594,13 @@ fn atomCount(self: *Plan9) usize {
589594 return data_nav_count + fn_nav_count + lazy_atom_count + extern_atom_count + uav_atom_count;
590595}
591596
592pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
597pub fn flushModule(
598 self: *Plan9,
599 arena: Allocator,
600 /// TODO: stop using this
601 tid: Zcu.PerThread.Id,
602 prog_node: std.Progress.Node,
603) link.File.FlushError!void {
593604 if (build_options.skip_non_native and builtin.object_format != .plan9) {
594605 @panic("Attempted to compile for object format that was disabled by build configuration");
595606 }
......@@ -600,6 +611,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
600611 _ = arena; // Has the same lifetime as the call to Compilation.update.
601612
602613 const comp = self.base.comp;
614 const diags = &comp.link_diags;
603615 const gpa = comp.gpa;
604616 const target = comp.root_mod.resolved_target.result;
605617
......@@ -611,7 +623,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
611623 defer assert(self.hdr.entry != 0x0);
612624
613625 const pt: Zcu.PerThread = .activate(
614 self.base.comp.zcu orelse return error.LinkingWithoutZigSourceUnimplemented,
626 self.base.comp.zcu orelse return diags.fail("linking without zig source unimplemented", .{}),
615627 tid,
616628 );
617629 defer pt.deactivate();
......@@ -620,22 +632,16 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
620632 if (self.lazy_syms.getPtr(.none)) |metadata| {
621633 // Most lazy symbols can be updated on first use, but
622634 // anyerror needs to wait for everything to be flushed.
623 if (metadata.text_state != .unused) self.updateLazySymbolAtom(
635 if (metadata.text_state != .unused) try self.updateLazySymbolAtom(
624636 pt,
625637 .{ .kind = .code, .ty = .anyerror_type },
626638 metadata.text_atom,
627 ) catch |err| return switch (err) {
628 error.CodegenFail => error.LinkFailure,
629 else => |e| e,
630 };
631 if (metadata.rodata_state != .unused) self.updateLazySymbolAtom(
639 );
640 if (metadata.rodata_state != .unused) try self.updateLazySymbolAtom(
632641 pt,
633642 .{ .kind = .const_data, .ty = .anyerror_type },
634643 metadata.rodata_atom,
635 ) catch |err| return switch (err) {
636 error.CodegenFail => error.LinkFailure,
637 else => |e| e,
638 };
644 );
639645 }
640646 for (self.lazy_syms.values()) |*metadata| {
641647 if (metadata.text_state != .unused) metadata.text_state = .flushed;
......@@ -908,8 +914,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
908914 }
909915 }
910916 }
911 // write it all!
912 try file.pwritevAll(iovecs, 0);
917 file.pwritevAll(iovecs, 0) catch |err| return diags.fail("failed to write file: {s}", .{@errorName(err)});
913918}
914919fn addNavExports(
915920 self: *Plan9,
......@@ -1047,8 +1052,15 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, pt: Zcu.PerThread, lazy_sym: F
10471052 return atom;
10481053}
10491054
1050fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, atom_index: Atom.Index) !void {
1055fn updateLazySymbolAtom(
1056 self: *Plan9,
1057 pt: Zcu.PerThread,
1058 sym: File.LazySymbol,
1059 atom_index: Atom.Index,
1060) error{ LinkFailure, OutOfMemory }!void {
10511061 const gpa = pt.zcu.gpa;
1062 const comp = self.base.comp;
1063 const diags = &comp.link_diags;
10521064
10531065 var required_alignment: InternPool.Alignment = .none;
10541066 var code_buffer = std.ArrayList(u8).init(gpa);
......@@ -1069,7 +1081,7 @@ fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, a
10691081
10701082 // generate the code
10711083 const src = Type.fromInterned(sym.ty).srcLocOrNull(pt.zcu) orelse Zcu.LazySrcLoc.unneeded;
1072 const res = try codegen.generateLazySymbol(
1084 const res = codegen.generateLazySymbol(
10731085 &self.base,
10741086 pt,
10751087 src,
......@@ -1078,13 +1090,14 @@ fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, a
10781090 &code_buffer,
10791091 .none,
10801092 .{ .atom_index = @intCast(atom_index) },
1081 );
1093 ) catch |err| switch (err) {
1094 error.OutOfMemory => return error.OutOfMemory,
1095 error.CodegenFail => return error.LinkFailure,
1096 error.Overflow => return diags.fail("codegen failure: encountered number too big for compiler", .{}),
1097 };
10821098 const code = switch (res) {
10831099 .ok => code_buffer.items,
1084 .fail => |em| {
1085 log.err("{s}", .{em.msg});
1086 return error.CodegenFail;
1087 },
1100 .fail => |em| return diags.fail("codegen failure: {s}", .{em.msg}),
10881101 };
10891102 // duped_code is freed when the atom is freed
10901103 const duped_code = try gpa.dupe(u8, code);
src/link/SpirV.zig+16-9
......@@ -206,7 +206,17 @@ pub fn flush(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
206206 return self.flushModule(arena, tid, prog_node);
207207}
208208
209pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
209pub fn flushModule(
210 self: *SpirV,
211 arena: Allocator,
212 tid: Zcu.PerThread.Id,
213 prog_node: std.Progress.Node,
214) link.File.FlushError!void {
215 // The goal is to never use this because it's only needed if we need to
216 // write to InternPool, but flushModule is too late to be writing to the
217 // InternPool.
218 _ = tid;
219
210220 if (build_options.skip_non_native) {
211221 @panic("Attempted to compile for architecture that was disabled by build configuration");
212222 }
......@@ -217,12 +227,11 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
217227 const sub_prog_node = prog_node.start("Flush Module", 0);
218228 defer sub_prog_node.end();
219229
220 const spv = &self.object.spv;
221
222230 const comp = self.base.comp;
231 const spv = &self.object.spv;
232 const diags = &comp.link_diags;
223233 const gpa = comp.gpa;
224234 const target = comp.getTarget();
225 _ = tid;
226235
227236 try writeCapabilities(spv, target);
228237 try writeMemoryModel(spv, target);
......@@ -265,13 +274,11 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
265274
266275 const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) {
267276 error.OutOfMemory => return error.OutOfMemory,
268 else => |other| {
269 log.err("error while linking: {s}", .{@errorName(other)});
270 return error.LinkFailure;
271 },
277 else => |other| return diags.fail("error while linking: {s}", .{@errorName(other)}),
272278 };
273279
274 try self.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module));
280 self.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module)) catch |err|
281 return diags.fail("failed to write: {s}", .{@errorName(err)});
275282}
276283
277284fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: std.Progress.Node) ![]Word {
src/link/Wasm.zig+137-25
......@@ -1,3 +1,14 @@
1//! The overall strategy here is to load all the object file data into memory
2//! as inputs are parsed. During `prelink`, as much linking as possible is
3//! performed without any knowledge of functions and globals provided by the
4//! Zcu. If there is no Zcu, effectively all linking is done in `prelink`.
5//!
6//! `updateFunc`, `updateNav`, `updateExports`, and `deleteExport` are handled
7//! by merely tracking references to the relevant functions and globals. All
8//! the linking logic between objects and Zcu happens in `flush`. Many
9//! components of the final output are computed on-the-fly at this time rather
10//! than being precomputed and stored separately.
11
112const Wasm = @This();
213const Archive = @import("Wasm/Archive.zig");
314const Object = @import("Wasm/Object.zig");
......@@ -164,10 +175,12 @@ functions: std.AutoArrayHashMapUnmanaged(FunctionImport.Resolution, void) = .emp
164175functions_len: u32 = 0,
165176/// Immutable after prelink. The undefined functions coming only from all object files.
166177/// The Zcu must satisfy these.
167function_imports_init: []FunctionImportId = &.{},
168/// Initialized as copy of `function_imports_init`; entries are deleted as
169/// they are satisfied by the Zcu.
170function_imports: std.AutoArrayHashMapUnmanaged(FunctionImportId, void) = .empty,
178function_imports_init_keys: []String = &.{},
179function_imports_init_vals: []FunctionImportId = &.{},
180/// Initialized as copy of `function_imports_init_keys` and
181/// `function_import_init_vals`; entries are deleted as they are satisfied by
182/// the Zcu.
183function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImportId) = .empty,
171184
172185/// Ordered list of non-import globals that will appear in the final binary.
173186/// Empty until prelink.
......@@ -175,38 +188,53 @@ globals: std.AutoArrayHashMapUnmanaged(GlobalImport.Resolution, void) = .empty,
175188/// Tracks the value at the end of prelink, at which point `globals`
176189/// contains only object file globals, and nothing from the Zcu yet.
177190globals_len: u32 = 0,
178global_imports_init: []GlobalImportId = &.{},
179global_imports: std.AutoArrayHashMapUnmanaged(GlobalImportId, void) = .empty,
191global_imports_init_keys: []String = &.{},
192global_imports_init_vals: []GlobalImportId = &.{},
193global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImportId) = .empty,
180194
181195/// Ordered list of non-import tables that will appear in the final binary.
182196/// Empty until prelink.
183197tables: std.AutoArrayHashMapUnmanaged(TableImport.Resolution, void) = .empty,
184table_imports: std.AutoArrayHashMapUnmanaged(ObjectTableImportIndex, void) = .empty,
198table_imports: std.AutoArrayHashMapUnmanaged(String, ObjectTableImportIndex) = .empty,
185199
186200any_exports_updated: bool = true,
187201
202/// Index into `objects`.
203pub const ObjectIndex = enum(u32) {
204 _,
205};
206
188207/// Index into `functions`.
189208pub const FunctionIndex = enum(u32) {
190209 _,
191210
192 pub fn fromNav(nav_index: InternPool.Nav.Index, wasm: *const Wasm) FunctionIndex {
193 return @enumFromInt(wasm.functions.getIndex(.pack(wasm, .{ .nav = nav_index })).?);
211 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?FunctionIndex {
212 const i = wasm.functions.getIndex(.fromIpNav(wasm, nav_index)) orelse return null;
213 return @enumFromInt(i);
194214 }
195215};
196216
197217/// 0. Index into `function_imports`
198218/// 1. Index into `functions`.
219///
220/// Note that function_imports indexes are subject to swap removals during
221/// `flush`.
199222pub const OutputFunctionIndex = enum(u32) {
200223 _,
201224};
202225
203226/// Index into `globals`.
204const GlobalIndex = enum(u32) {
227pub const GlobalIndex = enum(u32) {
205228 _,
206229
207230 fn key(index: GlobalIndex, f: *const Flush) *Wasm.GlobalImport.Resolution {
208231 return &f.globals.items[@intFromEnum(index)];
209232 }
233
234 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?GlobalIndex {
235 const i = wasm.globals.getIndex(.fromIpNav(wasm, nav_index)) orelse return null;
236 return @enumFromInt(i);
237 }
210238};
211239
212240/// The first N indexes correspond to input objects (`objects`) array.
......@@ -218,6 +246,38 @@ pub const SourceLocation = enum(u32) {
218246 zig_object_nofile = std.math.maxInt(u32) - 1,
219247 none = std.math.maxInt(u32),
220248 _,
249
250 /// Index into `source_locations`.
251 pub const Index = enum(u32) {
252 _,
253 };
254
255 pub const Unpacked = union(enum) {
256 none,
257 zig_object_nofile,
258 object_index: ObjectIndex,
259 source_location_index: Index,
260 };
261
262 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) SourceLocation {
263 _ = wasm;
264 return switch (unpacked) {
265 .zig_object_nofile => .zig_object_nofile,
266 .none => .none,
267 .object_index => |object_index| @enumFromInt(@intFromEnum(object_index)),
268 .source_location_index => @panic("TODO"),
269 };
270 }
271
272 pub fn addError(sl: SourceLocation, wasm: *Wasm, comptime f: []const u8, args: anytype) void {
273 const diags = &wasm.base.comp.link_diags;
274 switch (sl.unpack(wasm)) {
275 .none => unreachable,
276 .zig_object_nofile => diags.addError("zig compilation unit: " ++ f, args),
277 .object_index => |i| diags.addError("{}: " ++ f, .{wasm.objects.items[i].path} ++ args),
278 .source_location_index => @panic("TODO"),
279 }
280 }
221281};
222282
223283/// The lower bits of this ABI-match the flags here:
......@@ -445,6 +505,10 @@ pub const FunctionImport = extern struct {
445505 };
446506 }
447507
508 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {
509 return pack(wasm, .{ .nav = @enumFromInt(wasm.navs.getIndex(ip_nav).?) });
510 }
511
448512 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {
449513 return switch (r.unpack(wasm)) {
450514 .unresolved, .nav => true,
......@@ -587,6 +651,10 @@ pub const ObjectGlobalImportIndex = enum(u32) {
587651/// Index into `object_table_imports`.
588652pub const ObjectTableImportIndex = enum(u32) {
589653 _,
654
655 pub fn ptr(index: ObjectTableImportIndex, wasm: *const Wasm) *TableImport {
656 return &wasm.object_table_imports.items[@intFromEnum(index)];
657 }
590658};
591659
592660/// Index into `object_tables`.
......@@ -797,12 +865,48 @@ pub const ValtypeList = enum(u32) {
797865/// 1. Index into `imports`.
798866pub const FunctionImportId = enum(u32) {
799867 _,
868
869 /// This function is allowed O(N) lookup because it is only called during
870 /// diagnostic generation.
871 pub fn sourceLocation(id: FunctionImportId, wasm: *const Wasm) SourceLocation {
872 switch (id.unpack(wasm)) {
873 .object_function_import => |obj_func_index| {
874 // TODO binary search
875 for (wasm.objects.items, 0..) |o, i| {
876 if (o.function_imports.off <= obj_func_index and
877 o.function_imports.off + o.function_imports.len > obj_func_index)
878 {
879 return .pack(wasm, .{ .object_index = @enumFromInt(i) });
880 }
881 } else unreachable;
882 },
883 .zcu_import => return .zig_object_nofile, // TODO give a better source location
884 }
885 }
800886};
801887
802888/// 0. Index into `object_global_imports`.
803889/// 1. Index into `imports`.
804890pub const GlobalImportId = enum(u32) {
805891 _,
892
893 /// This function is allowed O(N) lookup because it is only called during
894 /// diagnostic generation.
895 pub fn sourceLocation(id: GlobalImportId, wasm: *const Wasm) SourceLocation {
896 switch (id.unpack(wasm)) {
897 .object_global_import => |obj_func_index| {
898 // TODO binary search
899 for (wasm.objects.items, 0..) |o, i| {
900 if (o.global_imports.off <= obj_func_index and
901 o.global_imports.off + o.global_imports.len > obj_func_index)
902 {
903 return .pack(wasm, .{ .object_index = @enumFromInt(i) });
904 }
905 } else unreachable;
906 },
907 .zcu_import => return .zig_object_nofile, // TODO give a better source location
908 }
909 }
806910};
807911
808912pub const Relocation = struct {
......@@ -897,7 +1001,7 @@ pub const InitFunc = extern struct {
8971001 priority: u32,
8981002 function_index: ObjectFunctionIndex,
8991003
900 fn lessThan(ctx: void, lhs: InitFunc, rhs: InitFunc) bool {
1004 pub fn lessThan(ctx: void, lhs: InitFunc, rhs: InitFunc) bool {
9011005 _ = ctx;
9021006 if (lhs.priority == rhs.priority) {
9031007 return @intFromEnum(lhs.function_index) < @intFromEnum(rhs.function_index);
......@@ -1237,18 +1341,19 @@ pub fn deinit(wasm: *Wasm) void {
12371341 wasm.object_comdat_symbols.deinit(gpa);
12381342 wasm.objects.deinit(gpa);
12391343
1240 wasm.atoms.deinit(gpa);
1241
12421344 wasm.synthetic_symbols.deinit(gpa);
1243 wasm.globals.deinit(gpa);
12441345 wasm.undefs.deinit(gpa);
12451346 wasm.discarded.deinit(gpa);
12461347 wasm.segments.deinit(gpa);
12471348 wasm.segment_info.deinit(gpa);
12481349
1249 wasm.global_imports.deinit(gpa);
12501350 wasm.func_types.deinit(gpa);
1351 wasm.function_exports.deinit(gpa);
1352 wasm.function_imports.deinit(gpa);
12511353 wasm.functions.deinit(gpa);
1354 wasm.globals.deinit(gpa);
1355 wasm.global_imports.deinit(gpa);
1356 wasm.table_imports.deinit(gpa);
12521357 wasm.output_globals.deinit(gpa);
12531358 wasm.exports.deinit(gpa);
12541359
......@@ -1340,13 +1445,19 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
13401445
13411446 if (!nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {
13421447 _ = wasm.imports.swapRemove(nav_index);
1343 _ = wasm.navs.swapRemove(nav_index); // TODO reclaim resources
1448 if (wasm.navs.swapRemove(nav_index)) |old| {
1449 _ = old;
1450 @panic("TODO reclaim resources");
1451 }
13441452 return;
13451453 }
13461454
13471455 if (is_extern) {
13481456 try wasm.imports.put(nav_index, {});
1349 _ = wasm.navs.swapRemove(nav_index); // TODO reclaim resources
1457 if (wasm.navs.swapRemove(nav_index)) |old| {
1458 _ = old;
1459 @panic("TODO reclaim resources");
1460 }
13501461 return;
13511462 }
13521463
......@@ -1528,7 +1639,8 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
15281639 }
15291640 }
15301641 wasm.functions_len = @intCast(wasm.functions.items.len);
1531 wasm.function_imports_init = try gpa.dupe(FunctionImportId, wasm.functions.keys());
1642 wasm.function_imports_init_keys = try gpa.dupe(String, wasm.function_imports.keys());
1643 wasm.function_imports_init_vals = try gpa.dupe(FunctionImportId, wasm.function_imports.vals());
15321644 wasm.function_exports_len = @intCast(wasm.function_exports.items.len);
15331645
15341646 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {
......@@ -1538,12 +1650,13 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
15381650 }
15391651 }
15401652 wasm.globals_len = @intCast(wasm.globals.items.len);
1541 wasm.global_imports_init = try gpa.dupe(GlobalImportId, wasm.globals.keys());
1653 wasm.global_imports_init_keys = try gpa.dupe(String, wasm.global_imports.keys());
1654 wasm.global_imports_init_vals = try gpa.dupe(GlobalImportId, wasm.global_imports.values());
15421655 wasm.global_exports_len = @intCast(wasm.global_exports.items.len);
15431656
1544 for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| {
1657 for (wasm.object_table_imports.items, 0..) |*import, i| {
15451658 if (import.flags.isIncluded(rdynamic)) {
1546 try markTable(wasm, name, import, @enumFromInt(i));
1659 try markTable(wasm, import.name, import, @enumFromInt(i));
15471660 continue;
15481661 }
15491662 }
......@@ -1581,7 +1694,7 @@ fn markFunction(
15811694 import.resolution = .__wasm_init_tls;
15821695 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});
15831696 } else {
1584 try wasm.function_imports.put(gpa, .fromObject(func_index), {});
1697 try wasm.function_imports.put(gpa, name, .fromObject(func_index));
15851698 }
15861699 } else {
15871700 const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);
......@@ -1631,7 +1744,7 @@ fn markGlobal(
16311744 import.resolution = .__tls_size;
16321745 wasm.globals.putAssumeCapacity(.__tls_size, {});
16331746 } else {
1634 try wasm.global_imports.put(gpa, .fromObject(global_index), {});
1747 try wasm.global_imports.put(gpa, name, .fromObject(global_index));
16351748 }
16361749 } else {
16371750 const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);
......@@ -1663,7 +1776,7 @@ fn markTable(
16631776 import.resolution = .__indirect_function_table;
16641777 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});
16651778 } else {
1666 try wasm.table_imports.put(gpa, .fromObject(table_index), {});
1779 try wasm.table_imports.put(gpa, name, .fromObject(table_index));
16671780 }
16681781 } else {
16691782 wasm.tables.putAssumeCapacity(import.resolution, {});
......@@ -1722,7 +1835,6 @@ pub fn flushModule(
17221835 defer sub_prog_node.end();
17231836
17241837 wasm.flush_buffer.clear();
1725 defer wasm.flush_buffer.subsequent = true;
17261838 return wasm.flush_buffer.finish(wasm, arena);
17271839}
17281840
src/link/Wasm/Flush.zig+32-35
......@@ -39,27 +39,17 @@ const DataSegmentIndex = enum(u32) {
3939
4040pub fn clear(f: *Flush) void {
4141 f.binary_bytes.clearRetainingCapacity();
42 f.function_imports.clearRetainingCapacity();
43 f.global_imports.clearRetainingCapacity();
44 f.functions.clearRetainingCapacity();
45 f.globals.clearRetainingCapacity();
4642 f.data_segments.clearRetainingCapacity();
4743 f.data_segment_groups.clearRetainingCapacity();
4844 f.indirect_function_table.clearRetainingCapacity();
49 f.function_exports.clearRetainingCapacity();
5045 f.global_exports.clearRetainingCapacity();
5146}
5247
5348pub fn deinit(f: *Flush, gpa: Allocator) void {
5449 f.binary_bytes.deinit(gpa);
55 f.function_imports.deinit(gpa);
56 f.global_imports.deinit(gpa);
57 f.functions.deinit(gpa);
58 f.globals.deinit(gpa);
5950 f.data_segments.deinit(gpa);
6051 f.data_segment_groups.deinit(gpa);
6152 f.indirect_function_table.deinit(gpa);
62 f.function_exports.deinit(gpa);
6353 f.global_exports.deinit(gpa);
6454 f.* = undefined;
6555}
......@@ -79,28 +69,32 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
7969
8070 if (wasm.any_exports_updated) {
8171 wasm.any_exports_updated = false;
72
8273 wasm.function_exports.shrinkRetainingCapacity(wasm.function_exports_len);
8374 wasm.global_exports.shrinkRetainingCapacity(wasm.global_exports_len);
8475
8576 const entry_name = if (wasm.entry_resolution.isNavOrUnresolved(wasm)) wasm.entry_name else .none;
8677
8778 try f.missing_exports.reinit(gpa, wasm.missing_exports_init, &.{});
79 try wasm.function_imports.reinit(gpa, wasm.function_imports_init_keys, wasm.function_imports_init_vals);
80 try wasm.global_imports.reinit(gpa, wasm.global_imports_init_keys, wasm.global_imports_init_vals);
81
8882 for (wasm.nav_exports.keys()) |*nav_export| {
8983 if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) {
90 try wasm.function_exports.append(gpa, .fromNav(nav_export.nav_index, wasm));
91 if (nav_export.name.toOptional() == entry_name) {
92 wasm.entry_resolution = .pack(wasm, .{ .nav = nav_export.nav_index });
93 } else {
94 f.missing_exports.swapRemove(nav_export.name);
95 }
84 try wasm.function_exports.append(gpa, Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?);
85 _ = f.missing_exports.swapRemove(nav_export.name);
86 _ = wasm.function_imports.swapRemove(nav_export.name);
87
88 if (nav_export.name.toOptional() == entry_name)
89 wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index);
9690 } else {
97 try wasm.global_exports.append(gpa, .fromNav(nav_export.nav_index));
98 f.missing_exports.swapRemove(nav_export.name);
91 try wasm.global_exports.append(gpa, Wasm.GlobalIndex.fromIpNav(wasm, nav_export.nav_index).?);
92 _ = f.missing_exports.swapRemove(nav_export.name);
93 _ = wasm.global_imports.swapRemove(nav_export.name);
9994 }
10095 }
10196
10297 for (f.missing_exports.keys()) |exp_name| {
103 if (exp_name != .none) continue;
10498 diags.addError("manually specified export name '{s}' undefined", .{exp_name.slice(wasm)});
10599 }
106100
......@@ -112,28 +106,31 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
112106 }
113107
114108 if (!allow_undefined) {
115 for (wasm.function_imports.keys()) |function_import_id| {
116 const name, const src_loc = function_import_id.nameAndLoc(wasm);
117 diags.addSrcError(src_loc, "undefined function: {s}", .{name.slice(wasm)});
109 for (wasm.function_imports.keys(), wasm.function_imports.values()) |name, function_import_id| {
110 const src_loc = function_import_id.sourceLocation(wasm);
111 src_loc.addError(wasm, "undefined function: {s}", .{name.slice(wasm)});
118112 }
119 for (wasm.global_imports.keys()) |global_import_id| {
120 const name, const src_loc = global_import_id.nameAndLoc(wasm);
121 diags.addSrcError(src_loc, "undefined global: {s}", .{name.slice(wasm)});
113 for (wasm.global_imports.keys(), wasm.global_imports.values()) |name, global_import_id| {
114 const src_loc = global_import_id.sourceLocation(wasm);
115 src_loc.addError(wasm, "undefined global: {s}", .{name.slice(wasm)});
122116 }
123 for (wasm.table_imports.keys()) |table_import_id| {
124 const name, const src_loc = table_import_id.nameAndLoc(wasm);
125 diags.addSrcError(src_loc, "undefined table: {s}", .{name.slice(wasm)});
117 for (wasm.table_imports.keys(), wasm.table_imports.values()) |name, table_import_id| {
118 const src_loc = table_import_id.ptr(wasm).source_location;
119 src_loc.addError(wasm, "undefined table: {s}", .{name.slice(wasm)});
126120 }
127121 }
128122
129123 if (diags.hasErrors()) return error.LinkFailure;
130124
125 wasm.functions.shrinkRetainingCapacity(wasm.functions_len);
126 wasm.globals.shrinkRetainingCapacity(wasm.globals_len);
127
131128 // TODO only include init functions for objects with must_link=true or
132129 // which have any alive functions inside them.
133130 if (wasm.object_init_funcs.items.len > 0) {
134131 // Zig has no constructors so these are only for object file inputs.
135132 mem.sortUnstable(Wasm.InitFunc, wasm.object_init_funcs.items, {}, Wasm.InitFunc.lessThan);
136 try f.functions.put(gpa, .__wasm_call_ctors, {});
133 try wasm.functions.put(gpa, .__wasm_call_ctors, {});
137134 }
138135
139136 var any_passive_inits = false;
......@@ -149,7 +146,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
149146 });
150147 }
151148
152 try f.functions.ensureUnusedCapacity(gpa, 3);
149 try wasm.functions.ensureUnusedCapacity(gpa, 3);
153150
154151 // Passive segments are used to avoid memory being reinitialized on each
155152 // thread's instantiation. These passive segments are initialized and
......@@ -157,14 +154,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
157154 // We also initialize bss segments (using memory.fill) as part of this
158155 // function.
159156 if (any_passive_inits) {
160 f.functions.putAssumeCapacity(.__wasm_init_memory, {});
157 wasm.functions.putAssumeCapacity(.__wasm_init_memory, {});
161158 }
162159
163160 // When we have TLS GOT entries and shared memory is enabled,
164161 // we must perform runtime relocations or else we don't create the function.
165162 if (shared_memory) {
166 if (f.need_tls_relocs) f.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {});
167 f.functions.putAssumeCapacity(gpa, .__wasm_init_tls, {});
163 if (f.need_tls_relocs) wasm.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {});
164 wasm.functions.putAssumeCapacity(gpa, .__wasm_init_tls, {});
168165 }
169166
170167 // Sort order:
......@@ -611,11 +608,11 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
611608 }
612609
613610 // Code section.
614 if (f.functions.count() != 0) {
611 if (wasm.functions.count() != 0) {
615612 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
616613 const start_offset = binary_bytes.items.len - 5; // minus 5 so start offset is 5 to include entry count
617614
618 for (f.functions.keys()) |resolution| switch (resolution.unpack()) {
615 for (wasm.functions.keys()) |resolution| switch (resolution.unpack()) {
619616 .unresolved => unreachable,
620617 .__wasm_apply_global_tls_relocs => @panic("TODO lower __wasm_apply_global_tls_relocs"),
621618 .__wasm_call_ctors => @panic("TODO lower __wasm_call_ctors"),
src/link/Wasm/Object.zig+25-15
......@@ -26,12 +26,14 @@ start_function: Wasm.OptionalObjectFunctionIndex,
2626/// (or therefore missing) and must generate an error when another object uses
2727/// features that are not supported by the other.
2828features: Wasm.Feature.Set,
29/// Points into Wasm functions
29/// Points into Wasm object_functions
3030functions: RelativeSlice,
31/// Points into Wasm object_globals_imports
32globals_imports: RelativeSlice,
33/// Points into Wasm object_tables_imports
34tables_imports: RelativeSlice,
31/// Points into Wasm object_function_imports
32function_imports: RelativeSlice,
33/// Points into Wasm object_global_imports
34global_imports: RelativeSlice,
35/// Points into Wasm object_table_imports
36table_imports: RelativeSlice,
3537/// Points into Wasm object_custom_segments
3638custom_segments: RelativeSlice,
3739/// For calculating local section index from `Wasm.SectionIndex`.
......@@ -180,13 +182,13 @@ fn parse(
180182
181183 const data_segment_start: u32 = @intCast(wasm.object_data_segments.items.len);
182184 const custom_segment_start: u32 = @intCast(wasm.object_custom_segments.items.len);
183 const imports_start: u32 = @intCast(wasm.object_imports.items.len);
184185 const functions_start: u32 = @intCast(wasm.object_functions.items.len);
185186 const tables_start: u32 = @intCast(wasm.object_tables.items.len);
186187 const memories_start: u32 = @intCast(wasm.object_memories.items.len);
187188 const globals_start: u32 = @intCast(wasm.object_globals.items.len);
188189 const init_funcs_start: u32 = @intCast(wasm.object_init_funcs.items.len);
189190 const comdats_start: u32 = @intCast(wasm.object_comdats.items.len);
191 const function_imports_start: u32 = @intCast(wasm.object_function_imports.items.len);
190192 const global_imports_start: u32 = @intCast(wasm.object_global_imports.items.len);
191193 const table_imports_start: u32 = @intCast(wasm.object_table_imports.items.len);
192194 const local_section_index_base = wasm.object_total_sections;
......@@ -504,7 +506,7 @@ fn parse(
504506 switch (kind) {
505507 .function => {
506508 const function, pos = readLeb(u32, bytes, pos);
507 try ss.function_imports.append(gpa, .{
509 try ss.func_imports.append(gpa, .{
508510 .module_name = interned_module_name,
509511 .name = interned_name,
510512 .index = function,
......@@ -854,13 +856,13 @@ fn parse(
854856 .archive_member_name = archive_member_name,
855857 .start_function = start_function,
856858 .features = features,
857 .imports = .{
858 .off = imports_start,
859 .len = @intCast(wasm.object_imports.items.len - imports_start),
860 },
861859 .functions = .{
862860 .off = functions_start,
863 .len = @intCast(wasm.functions.items.len - functions_start),
861 .len = @intCast(wasm.object_functions.items.len - functions_start),
862 },
863 .globals = .{
864 .off = globals_start,
865 .len = @intCast(wasm.object_globals.items.len - globals_start),
864866 },
865867 .tables = .{
866868 .off = tables_start,
......@@ -870,9 +872,17 @@ fn parse(
870872 .off = memories_start,
871873 .len = @intCast(wasm.object_memories.items.len - memories_start),
872874 },
873 .globals = .{
874 .off = globals_start,
875 .len = @intCast(wasm.object_globals.items.len - globals_start),
875 .function_imports = .{
876 .off = function_imports_start,
877 .len = @intCast(wasm.object_function_imports.items.len - function_imports_start),
878 },
879 .global_imports = .{
880 .off = global_imports_start,
881 .len = @intCast(wasm.object_global_imports.items.len - global_imports_start),
882 },
883 .table_imports = .{
884 .off = table_imports_start,
885 .len = @intCast(wasm.object_table_imports.items.len - table_imports_start),
876886 },
877887 .init_funcs = .{
878888 .off = init_funcs_start,