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...@@ -1728,7 +1728,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai
1728 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),1728 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
1729 error.LinkFailure => assert(comp.link_diags.hasErrors()),1729 error.LinkFailure => assert(comp.link_diags.hasErrors()),
1730 error.Overflow => {1730 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(
1732 gpa,1732 gpa,
1733 zcu.navSrcLoc(nav_index),1733 zcu.navSrcLoc(nav_index),
1734 "unable to codegen: {s}",1734 "unable to codegen: {s}",
...@@ -3114,7 +3114,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error...@@ -3114,7 +3114,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error
3114 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),3114 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
3115 error.LinkFailure => assert(comp.link_diags.hasErrors()),3115 error.LinkFailure => assert(comp.link_diags.hasErrors()),
3116 error.Overflow => {3116 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(
3118 gpa,3118 gpa,
3119 zcu.navSrcLoc(nav_index),3119 zcu.navSrcLoc(nav_index),
3120 "unable to codegen: {s}",3120 "unable to codegen: {s}",
src/link.zig+1-1
...@@ -745,7 +745,7 @@ pub const File = struct {...@@ -745,7 +745,7 @@ pub const File = struct {
745 }745 }
746746
747 pub const FlushError = error{747 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`.
749 LinkFailure,749 LinkFailure,
750 OutOfMemory,750 OutOfMemory,
751 };751 };
src/link/Coff.zig+3-6
...@@ -754,7 +754,7 @@ fn allocateGlobal(coff: *Coff) !u32 {...@@ -754,7 +754,7 @@ fn allocateGlobal(coff: *Coff) !u32 {
754 return index;754 return index;
755}755}
756756
757fn addGotEntry(coff: *Coff, target: SymbolWithLoc) !void {757fn addGotEntry(coff: *Coff, target: SymbolWithLoc) error{ OutOfMemory, LinkFailure }!void {
758 const gpa = coff.base.comp.gpa;758 const gpa = coff.base.comp.gpa;
759 if (coff.got_table.lookup.contains(target)) return;759 if (coff.got_table.lookup.contains(target)) return;
760 const got_index = try coff.got_table.allocateEntry(gpa, target);760 const got_index = try coff.got_table.allocateEntry(gpa, target);
...@@ -780,7 +780,7 @@ pub fn createAtom(coff: *Coff) !Atom.Index {...@@ -780,7 +780,7 @@ pub fn createAtom(coff: *Coff) !Atom.Index {
780 return atom_index;780 return atom_index;
781}781}
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 {
784 const atom = coff.getAtom(atom_index);784 const atom = coff.getAtom(atom_index);
785 const sym = atom.getSymbol(coff);785 const sym = atom.getSymbol(coff);
786 const align_ok = mem.alignBackward(u32, sym.value, alignment) == sym.value;786 const align_ok = mem.alignBackward(u32, sym.value, alignment) == sym.value;
...@@ -1313,10 +1313,7 @@ fn updateLazySymbolAtom(...@@ -1313,10 +1313,7 @@ fn updateLazySymbolAtom(
1313 };1313 };
1314 const code = switch (res) {1314 const code = switch (res) {
1315 .ok => code_buffer.items,1315 .ok => code_buffer.items,
1316 .fail => |em| {1316 .fail => |em| return diags.fail("failed to generate code: {s}", .{em.msg}),
1317 log.err("{s}", .{em.msg});
1318 return error.CodegenFail;
1319 },
1320 };1317 };
13211318
1322 const code_len: u32 = @intCast(code.len);1319 const code_len: u32 = @intCast(code.len);
src/link/Dwarf.zig+6-2
...@@ -23,6 +23,8 @@ debug_str: StringSection,...@@ -23,6 +23,8 @@ debug_str: StringSection,
23pub const UpdateError = error{23pub const UpdateError = error{
24 /// Indicates the error is already reported on `failed_codegen` in the Zcu.24 /// Indicates the error is already reported on `failed_codegen` in the Zcu.
25 CodegenFail,25 CodegenFail,
26 /// Indicates the error is already reported on `link_diags` in the Compilation.
27 LinkFailure,
26 OutOfMemory,28 OutOfMemory,
27};29};
2830
...@@ -590,12 +592,14 @@ const Unit = struct {...@@ -590,12 +592,14 @@ const Unit = struct {
590592
591 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {593 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
592 if (unit.off == new_off) return;594 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(
594 sec.off(dwarf) + unit.off,597 sec.off(dwarf) + unit.off,
595 dwarf.getFile().?,598 dwarf.getFile().?,
596 sec.off(dwarf) + new_off,599 sec.off(dwarf) + new_off,
597 unit.len,600 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", .{});
599 unit.off = new_off;603 unit.off = new_off;
600 }604 }
601605
src/link/Elf.zig+61-37
...@@ -575,7 +575,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) !?u64 {...@@ -575,7 +575,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) !?u64 {
575 }575 }
576 }576 }
577577
578 if (at_end) try self.base.file.?.setEndPos(end);578 if (at_end) try self.setEndPos(end);
579 return null;579 return null;
580}580}
581581
...@@ -638,7 +638,7 @@ pub fn growSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment:...@@ -638,7 +638,7 @@ pub fn growSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment:
638638
639 shdr.sh_offset = new_offset;639 shdr.sh_offset = new_offset;
640 } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {640 } 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);
642 }642 }
643 }643 }
644644
...@@ -960,7 +960,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -960,7 +960,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
960 },960 },
961 else => |e| return e,961 else => |e| return e,
962 };962 };
963 try self.base.file.?.pwriteAll(code, file_offset);963 try self.pwriteAll(code, file_offset);
964 }964 }
965965
966 if (has_reloc_errors) return error.LinkFailure;966 if (has_reloc_errors) return error.LinkFailure;
...@@ -2117,7 +2117,7 @@ pub fn writeShdrTable(self: *Elf) !void {...@@ -2117,7 +2117,7 @@ pub fn writeShdrTable(self: *Elf) !void {
2117 mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);2117 mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);
2118 }2118 }
2119 }2119 }
2120 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);2120 try self.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
2121 },2121 },
2122 .p64 => {2122 .p64 => {
2123 const buf = try gpa.alloc(elf.Elf64_Shdr, self.sections.items(.shdr).len);2123 const buf = try gpa.alloc(elf.Elf64_Shdr, self.sections.items(.shdr).len);
...@@ -2130,7 +2130,7 @@ pub fn writeShdrTable(self: *Elf) !void {...@@ -2130,7 +2130,7 @@ pub fn writeShdrTable(self: *Elf) !void {
2130 mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);2130 mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);
2131 }2131 }
2132 }2132 }
2133 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);2133 try self.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
2134 },2134 },
2135 }2135 }
2136}2136}
...@@ -2157,7 +2157,7 @@ fn writePhdrTable(self: *Elf) !void {...@@ -2157,7 +2157,7 @@ fn writePhdrTable(self: *Elf) !void {
2157 mem.byteSwapAllFields(elf.Elf32_Phdr, phdr);2157 mem.byteSwapAllFields(elf.Elf32_Phdr, phdr);
2158 }2158 }
2159 }2159 }
2160 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);2160 try self.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
2161 },2161 },
2162 .p64 => {2162 .p64 => {
2163 const buf = try gpa.alloc(elf.Elf64_Phdr, self.phdrs.items.len);2163 const buf = try gpa.alloc(elf.Elf64_Phdr, self.phdrs.items.len);
...@@ -2169,7 +2169,7 @@ fn writePhdrTable(self: *Elf) !void {...@@ -2169,7 +2169,7 @@ fn writePhdrTable(self: *Elf) !void {
2169 mem.byteSwapAllFields(elf.Elf64_Phdr, phdr);2169 mem.byteSwapAllFields(elf.Elf64_Phdr, phdr);
2170 }2170 }
2171 }2171 }
2172 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);2172 try self.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
2173 },2173 },
2174 }2174 }
2175}2175}
...@@ -2319,7 +2319,7 @@ pub fn writeElfHeader(self: *Elf) !void {...@@ -2319,7 +2319,7 @@ pub fn writeElfHeader(self: *Elf) !void {
23192319
2320 assert(index == e_ehsize);2320 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);
2323}2323}
23242324
2325pub fn freeNav(self: *Elf, nav: InternPool.Nav.Index) void {2325pub fn freeNav(self: *Elf, nav: InternPool.Nav.Index) void {
...@@ -2497,8 +2497,8 @@ pub fn writeMergeSections(self: *Elf) !void {...@@ -2497,8 +2497,8 @@ pub fn writeMergeSections(self: *Elf) !void {
24972497
2498 for (self.merge_sections.items) |*msec| {2498 for (self.merge_sections.items) |*msec| {
2499 const shdr = self.sections.items(.shdr)[msec.output_section_index];2499 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;2500 const fileoff = try self.cast(usize, msec.value + shdr.sh_offset);
2501 const size = math.cast(usize, msec.size) orelse return error.Overflow;2501 const size = try self.cast(usize, msec.size);
2502 try buffer.ensureTotalCapacity(size);2502 try buffer.ensureTotalCapacity(size);
2503 buffer.appendNTimesAssumeCapacity(0, size);2503 buffer.appendNTimesAssumeCapacity(0, size);
25042504
...@@ -2506,11 +2506,11 @@ pub fn writeMergeSections(self: *Elf) !void {...@@ -2506,11 +2506,11 @@ pub fn writeMergeSections(self: *Elf) !void {
2506 const msub = msec.mergeSubsection(msub_index);2506 const msub = msec.mergeSubsection(msub_index);
2507 assert(msub.alive);2507 assert(msub.alive);
2508 const string = msub.getString(self);2508 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);
2510 @memcpy(buffer.items[off..][0..string.len], string);2510 @memcpy(buffer.items[off..][0..string.len], string);
2511 }2511 }
25122512
2513 try self.base.file.?.pwriteAll(buffer.items, fileoff);2513 try self.pwriteAll(buffer.items, fileoff);
2514 buffer.clearRetainingCapacity();2514 buffer.clearRetainingCapacity();
2515 }2515 }
2516}2516}
...@@ -3682,7 +3682,7 @@ fn writeAtoms(self: *Elf) !void {...@@ -3682,7 +3682,7 @@ fn writeAtoms(self: *Elf) !void {
3682 const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset;3682 const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset;
3683 try th.write(self, buffer.writer());3683 try th.write(self, buffer.writer());
3684 assert(buffer.items.len == thunk_size);3684 assert(buffer.items.len == thunk_size);
3685 try self.base.file.?.pwriteAll(buffer.items, offset);3685 try self.pwriteAll(buffer.items, offset);
3686 buffer.clearRetainingCapacity();3686 buffer.clearRetainingCapacity();
3687 }3687 }
3688 }3688 }
...@@ -3790,12 +3790,12 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3790,12 +3790,12 @@ fn writeSyntheticSections(self: *Elf) !void {
3790 const contents = buffer[0 .. interp.len + 1];3790 const contents = buffer[0 .. interp.len + 1];
3791 const shdr = slice.items(.shdr)[shndx];3791 const shdr = slice.items(.shdr)[shndx];
3792 assert(shdr.sh_size == contents.len);3792 assert(shdr.sh_size == contents.len);
3793 try self.base.file.?.pwriteAll(contents, shdr.sh_offset);3793 try self.pwriteAll(contents, shdr.sh_offset);
3794 }3794 }
37953795
3796 if (self.section_indexes.hash) |shndx| {3796 if (self.section_indexes.hash) |shndx| {
3797 const shdr = slice.items(.shdr)[shndx];3797 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);
3799 }3799 }
38003800
3801 if (self.section_indexes.gnu_hash) |shndx| {3801 if (self.section_indexes.gnu_hash) |shndx| {
...@@ -3803,12 +3803,12 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3803,12 +3803,12 @@ fn writeSyntheticSections(self: *Elf) !void {
3803 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.gnu_hash.size());3803 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.gnu_hash.size());
3804 defer buffer.deinit();3804 defer buffer.deinit();
3805 try self.gnu_hash.write(self, buffer.writer());3805 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);
3807 }3807 }
38083808
3809 if (self.section_indexes.versym) |shndx| {3809 if (self.section_indexes.versym) |shndx| {
3810 const shdr = slice.items(.shdr)[shndx];3810 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);
3812 }3812 }
38133813
3814 if (self.section_indexes.verneed) |shndx| {3814 if (self.section_indexes.verneed) |shndx| {
...@@ -3816,7 +3816,7 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3816,7 +3816,7 @@ fn writeSyntheticSections(self: *Elf) !void {
3816 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.verneed.size());3816 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.verneed.size());
3817 defer buffer.deinit();3817 defer buffer.deinit();
3818 try self.verneed.write(buffer.writer());3818 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);
3820 }3820 }
38213821
3822 if (self.section_indexes.dynamic) |shndx| {3822 if (self.section_indexes.dynamic) |shndx| {
...@@ -3824,7 +3824,7 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3824,7 +3824,7 @@ fn writeSyntheticSections(self: *Elf) !void {
3824 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynamic.size(self));3824 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynamic.size(self));
3825 defer buffer.deinit();3825 defer buffer.deinit();
3826 try self.dynamic.write(self, buffer.writer());3826 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);
3828 }3828 }
38293829
3830 if (self.section_indexes.dynsymtab) |shndx| {3830 if (self.section_indexes.dynsymtab) |shndx| {
...@@ -3832,12 +3832,12 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3832,12 +3832,12 @@ fn writeSyntheticSections(self: *Elf) !void {
3832 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynsym.size());3832 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynsym.size());
3833 defer buffer.deinit();3833 defer buffer.deinit();
3834 try self.dynsym.write(self, buffer.writer());3834 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);
3836 }3836 }
38373837
3838 if (self.section_indexes.dynstrtab) |shndx| {3838 if (self.section_indexes.dynstrtab) |shndx| {
3839 const shdr = slice.items(.shdr)[shndx];3839 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);
3841 }3841 }
38423842
3843 if (self.section_indexes.eh_frame) |shndx| {3843 if (self.section_indexes.eh_frame) |shndx| {
...@@ -3847,21 +3847,21 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3847,21 +3847,21 @@ fn writeSyntheticSections(self: *Elf) !void {
3847 break :existing_size sym.atom(self).?.size;3847 break :existing_size sym.atom(self).?.size;
3848 };3848 };
3849 const shdr = slice.items(.shdr)[shndx];3849 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);
3851 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));3851 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
3852 defer buffer.deinit();3852 defer buffer.deinit();
3853 try eh_frame.writeEhFrame(self, buffer.writer());3853 try eh_frame.writeEhFrame(self, buffer.writer());
3854 assert(buffer.items.len == sh_size - existing_size);3854 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);
3856 }3856 }
38573857
3858 if (self.section_indexes.eh_frame_hdr) |shndx| {3858 if (self.section_indexes.eh_frame_hdr) |shndx| {
3859 const shdr = slice.items(.shdr)[shndx];3859 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);
3861 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);3861 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
3862 defer buffer.deinit();3862 defer buffer.deinit();
3863 try eh_frame.writeEhFrameHdr(self, buffer.writer());3863 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);
3865 }3865 }
38663866
3867 if (self.section_indexes.got) |index| {3867 if (self.section_indexes.got) |index| {
...@@ -3869,7 +3869,7 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3869,7 +3869,7 @@ fn writeSyntheticSections(self: *Elf) !void {
3869 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got.size(self));3869 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got.size(self));
3870 defer buffer.deinit();3870 defer buffer.deinit();
3871 try self.got.write(self, buffer.writer());3871 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);
3873 }3873 }
38743874
3875 if (self.section_indexes.rela_dyn) |shndx| {3875 if (self.section_indexes.rela_dyn) |shndx| {
...@@ -3877,7 +3877,7 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3877,7 +3877,7 @@ fn writeSyntheticSections(self: *Elf) !void {
3877 try self.got.addRela(self);3877 try self.got.addRela(self);
3878 try self.copy_rel.addRela(self);3878 try self.copy_rel.addRela(self);
3879 self.sortRelaDyn();3879 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);
3881 }3881 }
38823882
3883 if (self.section_indexes.plt) |shndx| {3883 if (self.section_indexes.plt) |shndx| {
...@@ -3885,7 +3885,7 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3885,7 +3885,7 @@ fn writeSyntheticSections(self: *Elf) !void {
3885 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt.size(self));3885 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt.size(self));
3886 defer buffer.deinit();3886 defer buffer.deinit();
3887 try self.plt.write(self, buffer.writer());3887 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);
3889 }3889 }
38903890
3891 if (self.section_indexes.got_plt) |shndx| {3891 if (self.section_indexes.got_plt) |shndx| {
...@@ -3893,7 +3893,7 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3893,7 +3893,7 @@ fn writeSyntheticSections(self: *Elf) !void {
3893 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got_plt.size(self));3893 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got_plt.size(self));
3894 defer buffer.deinit();3894 defer buffer.deinit();
3895 try self.got_plt.write(self, buffer.writer());3895 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);
3897 }3897 }
38983898
3899 if (self.section_indexes.plt_got) |shndx| {3899 if (self.section_indexes.plt_got) |shndx| {
...@@ -3901,13 +3901,13 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -3901,13 +3901,13 @@ fn writeSyntheticSections(self: *Elf) !void {
3901 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt_got.size(self));3901 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt_got.size(self));
3902 defer buffer.deinit();3902 defer buffer.deinit();
3903 try self.plt_got.write(self, buffer.writer());3903 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);
3905 }3905 }
39063906
3907 if (self.section_indexes.rela_plt) |shndx| {3907 if (self.section_indexes.rela_plt) |shndx| {
3908 const shdr = slice.items(.shdr)[shndx];3908 const shdr = slice.items(.shdr)[shndx];
3909 try self.plt.addRela(self);3909 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);
3911 }3911 }
39123912
3913 try self.writeSymtab();3913 try self.writeSymtab();
...@@ -3919,7 +3919,7 @@ pub fn writeShStrtab(self: *Elf) !void {...@@ -3919,7 +3919,7 @@ pub fn writeShStrtab(self: *Elf) !void {
3919 if (self.section_indexes.shstrtab) |index| {3919 if (self.section_indexes.shstrtab) |index| {
3920 const shdr = self.sections.items(.shdr)[index];3920 const shdr = self.sections.items(.shdr)[index];
3921 log.debug("writing .shstrtab from 0x{x} to 0x{x}", .{ shdr.sh_offset, shdr.sh_offset + shdr.sh_size });3921 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);
3923 }3923 }
3924}3924}
39253925
...@@ -3934,7 +3934,7 @@ pub fn writeSymtab(self: *Elf) !void {...@@ -3934,7 +3934,7 @@ pub fn writeSymtab(self: *Elf) !void {
3934 .p32 => @sizeOf(elf.Elf32_Sym),3934 .p32 => @sizeOf(elf.Elf32_Sym),
3935 .p64 => @sizeOf(elf.Elf64_Sym),3935 .p64 => @sizeOf(elf.Elf64_Sym),
3936 };3936 };
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
3939 log.debug("writing {d} symbols in .symtab from 0x{x} to 0x{x}", .{3939 log.debug("writing {d} symbols in .symtab from 0x{x} to 0x{x}", .{
3940 nsyms,3940 nsyms,
...@@ -3947,7 +3947,7 @@ pub fn writeSymtab(self: *Elf) !void {...@@ -3947,7 +3947,7 @@ pub fn writeSymtab(self: *Elf) !void {
3947 });3947 });
39483948
3949 try self.symtab.resize(gpa, nsyms);3949 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);
3951 // TODO we could resize instead and in ZigObject/Object always access as slice3951 // TODO we could resize instead and in ZigObject/Object always access as slice
3952 self.strtab.clearRetainingCapacity();3952 self.strtab.clearRetainingCapacity();
3953 self.strtab.appendAssumeCapacity(0);3953 self.strtab.appendAssumeCapacity(0);
...@@ -4016,17 +4016,17 @@ pub fn writeSymtab(self: *Elf) !void {...@@ -4016,17 +4016,17 @@ pub fn writeSymtab(self: *Elf) !void {
4016 };4016 };
4017 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);4017 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
4018 }4018 }
4019 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);4019 try self.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);
4020 },4020 },
4021 .p64 => {4021 .p64 => {
4022 if (foreign_endian) {4022 if (foreign_endian) {
4023 for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);4023 for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
4024 }4024 }
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);
4026 },4026 },
4027 }4027 }
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);
4030}4030}
40314031
4032/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.4032/// 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 {...@@ -5190,6 +5190,30 @@ pub fn stringTableLookup(strtab: []const u8, off: u32) [:0]const u8 {
5190 return slice[0..mem.indexOfScalar(u8, slice, 0).? :0];5190 return slice[0..mem.indexOfScalar(u8, slice, 0).? :0];
5191}5191}
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
5193const std = @import("std");5217const std = @import("std");
5194const build_options = @import("build_options");5218const build_options = @import("build_options");
5195const builtin = @import("builtin");5219const 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...@@ -434,7 +434,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
434 // libc/libSystem dep434 // libc/libSystem dep
435 self.resolveLibSystem(arena, comp, &system_libs) catch |err| switch (err) {435 self.resolveLibSystem(arena, comp, &system_libs) catch |err| switch (err) {
436 error.MissingLibSystem => {}, // already reported436 error.MissingLibSystem => {}, // already reported
437 else => |e| return e, // TODO: convert into an error437 else => |e| return diags.fail("failed to resolve libSystem: {s}", .{@errorName(e)}),
438 };438 };
439439
440 for (comp.link_inputs) |link_input| switch (link_input) {440 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...@@ -494,7 +494,10 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
494494
495 try self.resolveSymbols();495 try self.resolveSymbols();
496 try self.convertTentativeDefsAndResolveSpecialSymbols();496 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
499 if (self.base.gc_sections) {502 if (self.base.gc_sections) {
500 try dead_strip.gcAtoms(self);503 try dead_strip.gcAtoms(self);
...@@ -551,7 +554,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -551,7 +554,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
551554
552 try self.writeSectionsToFile();555 try self.writeSectionsToFile();
553 try self.allocateLinkeditSegment();556 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
556 var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: {563 var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: {
557 // Preallocate space for the code signature.564 // Preallocate space for the code signature.
...@@ -561,7 +568,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -561,7 +568,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
561 // where the code signature goes into.568 // where the code signature goes into.
562 var codesig = CodeSignature.init(self.getPageSize());569 var codesig = CodeSignature.init(self.getPageSize());
563 codesig.code_directory.ident = fs.path.basename(self.base.emit.sub_path);570 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) });
565 try self.writeCodeSignaturePadding(&codesig);573 try self.writeCodeSignaturePadding(&codesig);
566 break :blk codesig;574 break :blk codesig;
567 } else null;575 } else null;
...@@ -573,13 +581,29 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -573,13 +581,29 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
573 self.getPageSize(),581 self.getPageSize(),
574 );582 );
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 };
577 try self.writeHeader(ncmds, sizeofcmds);589 try self.writeHeader(ncmds, sizeofcmds);
578 try self.writeUuid(uuid_cmd_offset, self.requiresCodeSig());590 self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) {
579 if (self.getDebugSymbols()) |dsym| try dsym.flushModule(self);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.
581 if (codesig) |*csig| {601 if (codesig) |*csig| {
582 try self.writeCodeSignature(csig); // code signing always comes last602 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 };
583 const emit = self.base.emit;607 const emit = self.base.emit;
584 try invalidateKernelCache(emit.root_dir.handle, emit.sub_path);608 try invalidateKernelCache(emit.root_dir.handle, emit.sub_path);
585 }609 }
...@@ -2171,7 +2195,7 @@ fn allocateSections(self: *MachO) !void {...@@ -2171,7 +2195,7 @@ fn allocateSections(self: *MachO) !void {
2171 fileoff = mem.alignForward(u32, fileoff, page_size);2195 fileoff = mem.alignForward(u32, fileoff, page_size);
2172 }2196 }
21732197
2174 const alignment = try math.powi(u32, 2, header.@"align");2198 const alignment = try self.alignPow(header.@"align");
21752199
2176 vmaddr = mem.alignForward(u64, vmaddr, alignment);2200 vmaddr = mem.alignForward(u64, vmaddr, alignment);
2177 header.addr = vmaddr;2201 header.addr = vmaddr;
...@@ -2327,7 +2351,7 @@ fn allocateLinkeditSegment(self: *MachO) !void {...@@ -2327,7 +2351,7 @@ fn allocateLinkeditSegment(self: *MachO) !void {
2327 seg.vmaddr = mem.alignForward(u64, vmaddr, page_size);2351 seg.vmaddr = mem.alignForward(u64, vmaddr, page_size);
2328 seg.fileoff = mem.alignForward(u64, fileoff, page_size);2352 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);
2331 // DYLD_INFO_ONLY2355 // DYLD_INFO_ONLY
2332 {2356 {
2333 const cmd = &self.dyld_info_cmd;2357 const cmd = &self.dyld_info_cmd;
...@@ -2392,7 +2416,7 @@ fn resizeSections(self: *MachO) !void {...@@ -2392,7 +2416,7 @@ fn resizeSections(self: *MachO) !void {
2392 if (header.isZerofill()) continue;2416 if (header.isZerofill()) continue;
2393 if (self.isZigSection(@intCast(n_sect))) continue; // TODO this is horrible2417 if (self.isZigSection(@intCast(n_sect))) continue; // TODO this is horrible
2394 const cpu_arch = self.getTarget().cpu.arch;2418 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);
2396 try out.resize(self.base.comp.gpa, size);2420 try out.resize(self.base.comp.gpa, size);
2397 const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0;2421 const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0;
2398 @memset(out.items, padding_byte);2422 @memset(out.items, padding_byte);
...@@ -2489,7 +2513,7 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {...@@ -2489,7 +2513,7 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
24892513
2490 const doWork = struct {2514 const doWork = struct {
2491 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {2515 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);
2493 const size = th.size();2517 const size = th.size();
2494 var stream = std.io.fixedBufferStream(buffer[off..][0..size]);2518 var stream = std.io.fixedBufferStream(buffer[off..][0..size]);
2495 try th.write(macho_file, stream.writer());2519 try th.write(macho_file, stream.writer());
...@@ -2601,7 +2625,7 @@ fn writeSectionsToFile(self: *MachO) !void {...@@ -2601,7 +2625,7 @@ fn writeSectionsToFile(self: *MachO) !void {
26012625
2602 const slice = self.sections.slice();2626 const slice = self.sections.slice();
2603 for (slice.items(.header), slice.items(.out)) |header, out| {2627 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);
2605 }2629 }
2606}2630}
26072631
...@@ -2644,7 +2668,7 @@ fn writeDyldInfo(self: *MachO) !void {...@@ -2644,7 +2668,7 @@ fn writeDyldInfo(self: *MachO) !void {
2644 try self.lazy_bind_section.write(writer);2668 try self.lazy_bind_section.write(writer);
2645 try stream.seekTo(cmd.export_off - base_off);2669 try stream.seekTo(cmd.export_off - base_off);
2646 try self.export_trie.write(writer);2670 try self.export_trie.write(writer);
2647 try self.base.file.?.pwriteAll(buffer, cmd.rebase_off);2671 try self.pwriteAll(buffer, cmd.rebase_off);
2648}2672}
26492673
2650pub fn writeDataInCode(self: *MachO) !void {2674pub fn writeDataInCode(self: *MachO) !void {
...@@ -2655,7 +2679,7 @@ pub fn writeDataInCode(self: *MachO) !void {...@@ -2655,7 +2679,7 @@ pub fn writeDataInCode(self: *MachO) !void {
2655 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size());2679 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size());
2656 defer buffer.deinit();2680 defer buffer.deinit();
2657 try self.data_in_code.write(self, buffer.writer());2681 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);
2659}2683}
26602684
2661fn writeIndsymtab(self: *MachO) !void {2685fn writeIndsymtab(self: *MachO) !void {
...@@ -2667,15 +2691,15 @@ fn writeIndsymtab(self: *MachO) !void {...@@ -2667,15 +2691,15 @@ fn writeIndsymtab(self: *MachO) !void {
2667 var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size);2691 var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size);
2668 defer buffer.deinit();2692 defer buffer.deinit();
2669 try self.indsymtab.write(self, buffer.writer());2693 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);
2671}2695}
26722696
2673pub fn writeSymtabToFile(self: *MachO) !void {2697pub fn writeSymtabToFile(self: *MachO) !void {
2674 const tracy = trace(@src());2698 const tracy = trace(@src());
2675 defer tracy.end();2699 defer tracy.end();
2676 const cmd = self.symtab_cmd;2700 const cmd = self.symtab_cmd;
2677 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff);2701 try self.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff);
2678 try self.base.file.?.pwriteAll(self.strtab.items, cmd.stroff);2702 try self.pwriteAll(self.strtab.items, cmd.stroff);
2679}2703}
26802704
2681fn writeUnwindInfo(self: *MachO) !void {2705fn writeUnwindInfo(self: *MachO) !void {
...@@ -2686,20 +2710,20 @@ fn writeUnwindInfo(self: *MachO) !void {...@@ -2686,20 +2710,20 @@ fn writeUnwindInfo(self: *MachO) !void {
26862710
2687 if (self.eh_frame_sect_index) |index| {2711 if (self.eh_frame_sect_index) |index| {
2688 const header = self.sections.items(.header)[index];2712 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);
2690 const buffer = try gpa.alloc(u8, size);2714 const buffer = try gpa.alloc(u8, size);
2691 defer gpa.free(buffer);2715 defer gpa.free(buffer);
2692 eh_frame.write(self, buffer);2716 eh_frame.write(self, buffer);
2693 try self.base.file.?.pwriteAll(buffer, header.offset);2717 try self.pwriteAll(buffer, header.offset);
2694 }2718 }
26952719
2696 if (self.unwind_info_sect_index) |index| {2720 if (self.unwind_info_sect_index) |index| {
2697 const header = self.sections.items(.header)[index];2721 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);
2699 const buffer = try gpa.alloc(u8, size);2723 const buffer = try gpa.alloc(u8, size);
2700 defer gpa.free(buffer);2724 defer gpa.free(buffer);
2701 try self.unwind_info.write(self, buffer);2725 try self.unwind_info.write(self, buffer);
2702 try self.base.file.?.pwriteAll(buffer, header.offset);2726 try self.pwriteAll(buffer, header.offset);
2703 }2727 }
2704}2728}
27052729
...@@ -2890,7 +2914,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2890,7 +2914,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
28902914
2891 assert(stream.pos == needed_size);2915 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
2895 return .{ ncmds, buffer.len, uuid_cmd_offset };2919 return .{ ncmds, buffer.len, uuid_cmd_offset };
2896}2920}
...@@ -2944,7 +2968,7 @@ fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {...@@ -2944,7 +2968,7 @@ fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {
29442968
2945 log.debug("writing Mach-O header {}", .{header});2969 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);
2948}2972}
29492973
2950fn writeUuid(self: *MachO, uuid_cmd_offset: u64, has_codesig: bool) !void {2974fn 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 {...@@ -2954,7 +2978,7 @@ fn writeUuid(self: *MachO, uuid_cmd_offset: u64, has_codesig: bool) !void {
2954 } else self.codesig_cmd.dataoff;2978 } else self.codesig_cmd.dataoff;
2955 try calcUuid(self.base.comp, self.base.file.?, file_size, &self.uuid_cmd.uuid);2979 try calcUuid(self.base.comp, self.base.file.?, file_size, &self.uuid_cmd.uuid);
2956 const offset = uuid_cmd_offset + @sizeOf(macho.load_command);2980 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);
2958}2982}
29592983
2960pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {2984pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
...@@ -2968,7 +2992,7 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {...@@ -2968,7 +2992,7 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
2968 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ offset, offset + needed_size });2992 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
2969 // Pad out the space. We need to do this to calculate valid hashes for everything in the file2993 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
2970 // except for code signature data.2994 // 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
2973 self.codesig_cmd.dataoff = @as(u32, @intCast(offset));2997 self.codesig_cmd.dataoff = @as(u32, @intCast(offset));
2974 self.codesig_cmd.datasize = @as(u32, @intCast(needed_size));2998 self.codesig_cmd.datasize = @as(u32, @intCast(needed_size));
...@@ -2995,7 +3019,7 @@ pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {...@@ -2995,7 +3019,7 @@ pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
2995 offset + buffer.items.len,3019 offset + buffer.items.len,
2996 });3020 });
29973021
2998 try self.base.file.?.pwriteAll(buffer.items, offset);3022 try self.pwriteAll(buffer.items, offset);
2999}3023}
30003024
3001pub fn updateFunc(3025pub fn updateFunc(
...@@ -3109,7 +3133,7 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) !?u64 {...@@ -3109,7 +3133,7 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) !?u64 {
3109 }3133 }
3110 }3134 }
31113135
3112 if (at_end) try self.base.file.?.setEndPos(end);3136 if (at_end) try self.setEndPos(end);
3113 return null;3137 return null;
3114}3138}
31153139
...@@ -3193,22 +3217,25 @@ pub fn findFreeSpaceVirtual(self: *MachO, object_size: u64, min_alignment: u32)...@@ -3193,22 +3217,25 @@ pub fn findFreeSpaceVirtual(self: *MachO, object_size: u64, min_alignment: u32)
3193 return start;3217 return start;
3194}3218}
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;
3197 const file = self.base.file.?;3222 const file = self.base.file.?;
3198 const amt = try file.copyRangeAll(old_offset, file, new_offset, size);3223 const amt = file.copyRangeAll(old_offset, file, new_offset, size) catch |err|
3199 if (amt != size) return error.InputOutput;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", .{});
3200}3227}
32013228
3202/// Like File.copyRangeAll but also ensures the source region is zeroed out after copy.3229/// Like File.copyRangeAll but also ensures the source region is zeroed out after copy.
3203/// This is so that we guarantee zeroed out regions for mapping of zerofill sections by the loader.3230/// 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 {
3205 const gpa = self.base.comp.gpa;3232 const gpa = self.base.comp.gpa;
3206 try self.copyRangeAll(old_offset, new_offset, size);3233 try self.copyRangeAll(old_offset, new_offset, size);
3207 const size_u = math.cast(usize, size) orelse return error.Overflow;3234 const size_u = try self.cast(usize, size);
3208 const zeroes = try gpa.alloc(u8, size_u);3235 const zeroes = try gpa.alloc(u8, size_u); // TODO no need to allocate here.
3209 defer gpa.free(zeroes);3236 defer gpa.free(zeroes);
3210 @memset(zeroes, 0);3237 @memset(zeroes, 0);
3211 try self.base.file.?.pwriteAll(zeroes, old_offset);3238 try self.pwriteAll(zeroes, old_offset);
3212}3239}
32133240
3214const InitMetadataOptions = struct {3241const InitMetadataOptions = struct {
...@@ -3312,10 +3339,9 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3312,10 +3339,9 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3312 const allocSect = struct {3339 const allocSect = struct {
3313 fn allocSect(macho_file: *MachO, sect_id: u8, size: u64) !void {3340 fn allocSect(macho_file: *MachO, sect_id: u8, size: u64) !void {
3314 const sect = &macho_file.sections.items(.header)[sect_id];3341 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");
3316 if (!sect.isZerofill()) {3343 if (!sect.isZerofill()) {
3317 sect.offset = math.cast(u32, try macho_file.findFreeSpace(size, alignment)) orelse3344 sect.offset = try macho_file.cast(u32, try macho_file.findFreeSpace(size, alignment));
3318 return error.Overflow;
3319 }3345 }
3320 sect.addr = macho_file.findFreeSpaceVirtual(size, alignment);3346 sect.addr = macho_file.findFreeSpaceVirtual(size, alignment);
3321 sect.size = size;3347 sect.size = size;
...@@ -3397,7 +3423,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3397,7 +3423,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3397 };3423 };
3398}3424}
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 {
3401 if (self.base.isRelocatable()) {3427 if (self.base.isRelocatable()) {
3402 try self.growSectionRelocatable(sect_index, needed_size);3428 try self.growSectionRelocatable(sect_index, needed_size);
3403 } else {3429 } else {
...@@ -3405,7 +3431,7 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {...@@ -3405,7 +3431,7 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
3405 }3431 }
3406}3432}
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 {
3409 const diags = &self.base.comp.link_diags;3435 const diags = &self.base.comp.link_diags;
3410 const sect = &self.sections.items(.header)[sect_index];3436 const sect = &self.sections.items(.header)[sect_index];
34113437
...@@ -3433,7 +3459,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo...@@ -3433,7 +3459,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
34333459
3434 sect.offset = @intCast(new_offset);3460 sect.offset = @intCast(new_offset);
3435 } else if (sect.offset + allocated_size == std.math.maxInt(u64)) {3461 } 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);
3437 }3463 }
3438 seg.filesize = needed_size;3464 seg.filesize = needed_size;
3439 }3465 }
...@@ -3454,7 +3480,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo...@@ -3454,7 +3480,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
3454 seg.vmsize = needed_size;3480 seg.vmsize = needed_size;
3455}3481}
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 {
3458 const sect = &self.sections.items(.header)[sect_index];3484 const sect = &self.sections.items(.header)[sect_index];
34593485
3460 if (!sect.isZerofill()) {3486 if (!sect.isZerofill()) {
...@@ -3464,7 +3490,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void...@@ -3464,7 +3490,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
3464 sect.size = 0;3490 sect.size = 0;
34653491
3466 // Must move the entire section.3492 // Must move the entire section.
3467 const alignment = try math.powi(u32, 2, sect.@"align");3493 const alignment = try self.alignPow(sect.@"align");
3468 const new_offset = try self.findFreeSpace(needed_size, alignment);3494 const new_offset = try self.findFreeSpace(needed_size, alignment);
3469 const new_addr = self.findFreeSpaceVirtual(needed_size, alignment);3495 const new_addr = self.findFreeSpaceVirtual(needed_size, alignment);
34703496
...@@ -3482,7 +3508,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void...@@ -3482,7 +3508,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
3482 sect.offset = @intCast(new_offset);3508 sect.offset = @intCast(new_offset);
3483 sect.addr = new_addr;3509 sect.addr = new_addr;
3484 } else if (sect.offset + allocated_size == std.math.maxInt(u64)) {3510 } 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);
3486 }3512 }
3487 }3513 }
3488 sect.size = needed_size;3514 sect.size = needed_size;
...@@ -5316,6 +5342,40 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {...@@ -5316,6 +5342,40 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
5316 return true;5342 return true;
5317}5343}
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
5319/// Branch instruction has 26 bits immediate but is 4 byte aligned.5379/// Branch instruction has 26 bits immediate but is 4 byte aligned.
5320const jump_bits = @bitSizeOf(i28);5380const jump_bits = @bitSizeOf(i28);
5321const max_distance = (1 << (jump_bits - 1));5381const 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 {...@@ -971,7 +971,7 @@ pub fn calcNumRelocs(self: Atom, macho_file: *MachO) u32 {
971 }971 }
972}972}
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 {
975 const tracy = trace(@src());975 const tracy = trace(@src());
976 defer tracy.end();976 defer tracy.end();
977977
...@@ -983,15 +983,15 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r...@@ -983,15 +983,15 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
983 var i: usize = 0;983 var i: usize = 0;
984 for (relocs) |rel| {984 for (relocs) |rel| {
985 defer i += 1;985 defer i += 1;
986 const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;986 const rel_offset = try macho_file.cast(usize, rel.offset - self.off);
987 const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow;987 const r_address: i32 = try macho_file.cast(i32, self.value + rel_offset);
988 assert(r_address >= 0);988 assert(r_address >= 0);
989 const r_symbolnum = r_symbolnum: {989 const r_symbolnum = r_symbolnum: {
990 const r_symbolnum: u32 = switch (rel.tag) {990 const r_symbolnum: u32 = switch (rel.tag) {
991 .local => rel.getTargetAtom(self, macho_file).out_n_sect + 1,991 .local => rel.getTargetAtom(self, macho_file).out_n_sect + 1,
992 .@"extern" => rel.getTargetSymbol(self, macho_file).getOutputSymtabIndex(macho_file).?,992 .@"extern" => rel.getTargetSymbol(self, macho_file).getOutputSymtabIndex(macho_file).?,
993 };993 };
994 break :r_symbolnum math.cast(u24, r_symbolnum) orelse return error.Overflow;994 break :r_symbolnum try macho_file.cast(u24, r_symbolnum);
995 };995 };
996 const r_extern = rel.tag == .@"extern";996 const r_extern = rel.tag == .@"extern";
997 var addend = rel.addend + rel.getRelocAddend(cpu_arch);997 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...@@ -1027,7 +1027,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
1027 } else if (addend > 0) {1027 } else if (addend > 0) {
1028 buffer[i] = .{1028 buffer[i] = .{
1029 .r_address = r_address,1029 .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)),
1031 .r_pcrel = 0,1031 .r_pcrel = 0,
1032 .r_length = 2,1032 .r_length = 2,
1033 .r_extern = 0,1033 .r_extern = 0,
src/link/MachO/InternalObject.zig+9-7
...@@ -414,10 +414,11 @@ pub fn resolveLiterals(self: *InternalObject, lp: *MachO.LiteralPool, macho_file...@@ -414,10 +414,11 @@ pub fn resolveLiterals(self: *InternalObject, lp: *MachO.LiteralPool, macho_file
414 const rel = relocs[0];414 const rel = relocs[0];
415 assert(rel.tag == .@"extern");415 assert(rel.tag == .@"extern");
416 const target = rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?;416 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);
418 try buffer.ensureUnusedCapacity(target_size);418 try buffer.ensureUnusedCapacity(target_size);
419 buffer.resize(target_size) catch unreachable;419 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);
421 const res = try lp.insert(gpa, header.type(), buffer.items);422 const res = try lp.insert(gpa, header.type(), buffer.items);
422 buffer.clearRetainingCapacity();423 buffer.clearRetainingCapacity();
423 if (!res.found_existing) {424 if (!res.found_existing) {
...@@ -607,10 +608,11 @@ pub fn writeAtoms(self: *InternalObject, macho_file: *MachO) !void {...@@ -607,10 +608,11 @@ pub fn writeAtoms(self: *InternalObject, macho_file: *MachO) !void {
607 if (!atom.isAlive()) continue;608 if (!atom.isAlive()) continue;
608 const sect = atom.getInputSection(macho_file);609 const sect = atom.getInputSection(macho_file);
609 if (sect.isZerofill()) continue;610 if (sect.isZerofill()) continue;
610 const off = std.math.cast(usize, atom.value) orelse return error.Overflow;611 const off = try macho_file.cast(usize, atom.value);
611 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;612 const size = try macho_file.cast(usize, atom.size);
612 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items[off..][0..size];613 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);
614 try atom.resolveRelocs(macho_file, buffer);616 try atom.resolveRelocs(macho_file, buffer);
615 }617 }
616}618}
...@@ -644,13 +646,13 @@ fn addSection(self: *InternalObject, allocator: Allocator, segname: []const u8,...@@ -644,13 +646,13 @@ fn addSection(self: *InternalObject, allocator: Allocator, segname: []const u8,
644 return n_sect;646 return n_sect;
645}647}
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 {
648 const slice = self.sections.slice();650 const slice = self.sections.slice();
649 assert(index < slice.items(.header).len);651 assert(index < slice.items(.header).len);
650 const sect = slice.items(.header)[index];652 const sect = slice.items(.header)[index];
651 const extra = slice.items(.extra)[index];653 const extra = slice.items(.extra)[index];
652 if (extra.is_objc_methname) {654 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);
654 return self.objc_methnames.items[sect.offset..][0..size];656 return self.objc_methnames.items[sect.offset..][0..size];
655 } else if (extra.is_objc_selref)657 } else if (extra.is_objc_selref)
656 return &self.objc_selrefs658 return &self.objc_selrefs
src/link/MachO/Object.zig+32-34
...@@ -582,7 +582,7 @@ fn initPointerLiterals(self: *Object, allocator: Allocator, macho_file: *MachO)...@@ -582,7 +582,7 @@ fn initPointerLiterals(self: *Object, allocator: Allocator, macho_file: *MachO)
582 );582 );
583 return error.MalformedObject;583 return error.MalformedObject;
584 }584 }
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
587 for (0..num_ptrs) |i| {587 for (0..num_ptrs) |i| {
588 const pos: u32 = @as(u32, @intCast(i)) * rec_size;588 const pos: u32 = @as(u32, @intCast(i)) * rec_size;
...@@ -650,8 +650,8 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO...@@ -650,8 +650,8 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
650650
651 for (subs.items) |sub| {651 for (subs.items) |sub| {
652 const atom = self.getAtom(sub.atom).?;652 const atom = self.getAtom(sub.atom).?;
653 const atom_off = math.cast(usize, atom.off) orelse return error.Overflow;653 const atom_off = try macho_file.cast(usize, atom.off);
654 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;654 const atom_size = try macho_file.cast(usize, atom.size);
655 const atom_data = data[atom_off..][0..atom_size];655 const atom_data = data[atom_off..][0..atom_size];
656 const res = try lp.insert(gpa, header.type(), atom_data);656 const res = try lp.insert(gpa, header.type(), atom_data);
657 if (!res.found_existing) {657 if (!res.found_existing) {
...@@ -674,8 +674,8 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO...@@ -674,8 +674,8 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
674 .local => rel.getTargetAtom(atom.*, macho_file),674 .local => rel.getTargetAtom(atom.*, macho_file),
675 .@"extern" => rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?,675 .@"extern" => rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?,
676 };676 };
677 const addend = math.cast(u32, rel.addend) orelse return error.Overflow;677 const addend = try macho_file.cast(u32, rel.addend);
678 const target_size = math.cast(usize, target.size) orelse return error.Overflow;678 const target_size = try macho_file.cast(usize, target.size);
679 try buffer.ensureUnusedCapacity(target_size);679 try buffer.ensureUnusedCapacity(target_size);
680 buffer.resize(target_size) catch unreachable;680 buffer.resize(target_size) catch unreachable;
681 const gop = try sections_data.getOrPut(target.n_sect);681 const gop = try sections_data.getOrPut(target.n_sect);
...@@ -683,7 +683,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO...@@ -683,7 +683,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
683 gop.value_ptr.* = try self.readSectionData(gpa, file, @intCast(target.n_sect));683 gop.value_ptr.* = try self.readSectionData(gpa, file, @intCast(target.n_sect));
684 }684 }
685 const data = gop.value_ptr.*;685 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);
687 @memcpy(buffer.items, data[target_off..][0..target_size]);687 @memcpy(buffer.items, data[target_off..][0..target_size]);
688 const res = try lp.insert(gpa, header.type(), buffer.items[addend..]);688 const res = try lp.insert(gpa, header.type(), buffer.items[addend..]);
689 buffer.clearRetainingCapacity();689 buffer.clearRetainingCapacity();
...@@ -1033,7 +1033,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi...@@ -1033,7 +1033,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi
1033 const sect = slice.items(.header)[sect_id];1033 const sect = slice.items(.header)[sect_id];
1034 const relocs = slice.items(.relocs)[sect_id];1034 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);
1037 try self.eh_frame_data.resize(allocator, size);1037 try self.eh_frame_data.resize(allocator, size);
1038 const amt = try file.preadAll(self.eh_frame_data.items, sect.offset + self.offset);1038 const amt = try file.preadAll(self.eh_frame_data.items, sect.offset + self.offset);
1039 if (amt != self.eh_frame_data.items.len) return error.InputOutput;1039 if (amt != self.eh_frame_data.items.len) return error.InputOutput;
...@@ -1696,7 +1696,7 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {...@@ -1696,7 +1696,7 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
16961696
1697pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {1697pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
1698 // Header1698 // 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);
1700 const basename = std.fs.path.basename(self.path.sub_path);1700 const basename = std.fs.path.basename(self.path.sub_path);
1701 try Archive.writeHeader(basename, size, ar_format, writer);1701 try Archive.writeHeader(basename, size, ar_format, writer);
1702 // Data1702 // Data
...@@ -1826,7 +1826,7 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void {...@@ -1826,7 +1826,7 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void {
18261826
1827 for (headers, 0..) |header, n_sect| {1827 for (headers, 0..) |header, n_sect| {
1828 if (header.isZerofill()) continue;1828 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);
1830 const data = try gpa.alloc(u8, size);1830 const data = try gpa.alloc(u8, size);
1831 const amt = try file.preadAll(data, header.offset + self.offset);1831 const amt = try file.preadAll(data, header.offset + self.offset);
1832 if (amt != data.len) return error.InputOutput;1832 if (amt != data.len) return error.InputOutput;
...@@ -1837,9 +1837,9 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void {...@@ -1837,9 +1837,9 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void {
1837 if (!atom.isAlive()) continue;1837 if (!atom.isAlive()) continue;
1838 const sect = atom.getInputSection(macho_file);1838 const sect = atom.getInputSection(macho_file);
1839 if (sect.isZerofill()) continue;1839 if (sect.isZerofill()) continue;
1840 const value = math.cast(usize, atom.value) orelse return error.Overflow;1840 const value = try macho_file.cast(usize, atom.value);
1841 const off = math.cast(usize, atom.off) orelse return error.Overflow;1841 const off = try macho_file.cast(usize, atom.off);
1842 const size = math.cast(usize, atom.size) orelse return error.Overflow;1842 const size = try macho_file.cast(usize, atom.size);
1843 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;1843 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;
1844 const data = sections_data[atom.n_sect];1844 const data = sections_data[atom.n_sect];
1845 @memcpy(buffer[value..][0..size], data[off..][0..size]);1845 @memcpy(buffer[value..][0..size], data[off..][0..size]);
...@@ -1865,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {...@@ -1865,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
18651865
1866 for (headers, 0..) |header, n_sect| {1866 for (headers, 0..) |header, n_sect| {
1867 if (header.isZerofill()) continue;1867 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);
1869 const data = try gpa.alloc(u8, size);1869 const data = try gpa.alloc(u8, size);
1870 const amt = try file.preadAll(data, header.offset + self.offset);1870 const amt = try file.preadAll(data, header.offset + self.offset);
1871 if (amt != data.len) return error.InputOutput;1871 if (amt != data.len) return error.InputOutput;
...@@ -1876,9 +1876,9 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {...@@ -1876,9 +1876,9 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
1876 if (!atom.isAlive()) continue;1876 if (!atom.isAlive()) continue;
1877 const sect = atom.getInputSection(macho_file);1877 const sect = atom.getInputSection(macho_file);
1878 if (sect.isZerofill()) continue;1878 if (sect.isZerofill()) continue;
1879 const value = math.cast(usize, atom.value) orelse return error.Overflow;1879 const value = try macho_file.cast(usize, atom.value);
1880 const off = math.cast(usize, atom.off) orelse return error.Overflow;1880 const off = try macho_file.cast(usize, atom.off);
1881 const size = math.cast(usize, atom.size) orelse return error.Overflow;1881 const size = try macho_file.cast(usize, atom.size);
1882 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;1882 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;
1883 const data = sections_data[atom.n_sect];1883 const data = sections_data[atom.n_sect];
1884 @memcpy(buffer[value..][0..size], data[off..][0..size]);1884 @memcpy(buffer[value..][0..size], data[off..][0..size]);
...@@ -1909,29 +1909,27 @@ pub fn calcCompactUnwindSizeRelocatable(self: *Object, macho_file: *MachO) void...@@ -1909,29 +1909,27 @@ pub fn calcCompactUnwindSizeRelocatable(self: *Object, macho_file: *MachO) void
1909 }1909 }
1910}1910}
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
1912pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {1927pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {
1913 const tracy = trace(@src());1928 const tracy = trace(@src());
1914 defer tracy.end();1929 defer tracy.end();
19151930
1916 const cpu_arch = macho_file.getTarget().cpu.arch;1931 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
1935 const nsect = macho_file.unwind_info_sect_index.?;1933 const nsect = macho_file.unwind_info_sect_index.?;
1936 const buffer = macho_file.sections.items(.out)[nsect].items;1934 const buffer = macho_file.sections.items(.out)[nsect].items;
1937 const relocs = macho_file.sections.items(.relocs)[nsect].items;1935 const relocs = macho_file.sections.items(.relocs)[nsect].items;
...@@ -1967,7 +1965,7 @@ pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {...@@ -1967,7 +1965,7 @@ pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void {
19671965
1968 // Personality function1966 // Personality function
1969 if (rec.getPersonality(macho_file)) |sym| {1967 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).?);
1971 var reloc = try addReloc(offset + 16, cpu_arch);1969 var reloc = try addReloc(offset + 16, cpu_arch);
1972 reloc.r_symbolnum = r_symbolnum;1970 reloc.r_symbolnum = r_symbolnum;
1973 reloc.r_extern = 1;1971 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...@@ -290,12 +290,15 @@ pub fn dedupLiterals(self: *ZigObject, lp: MachO.LiteralPool, macho_file: *MachO
290/// We need this so that we can write to an archive.290/// We need this so that we can write to an archive.
291/// TODO implement writing ZigObject data directly to a buffer instead.291/// TODO implement writing ZigObject data directly to a buffer instead.
292pub fn readFileContents(self: *ZigObject, macho_file: *MachO) !void {292pub fn readFileContents(self: *ZigObject, macho_file: *MachO) !void {
293 const diags = &macho_file.base.comp.link_diags;
293 // Size of the output object file is always the offset + size of the strtab294 // Size of the output object file is always the offset + size of the strtab
294 const size = macho_file.symtab_cmd.stroff + macho_file.symtab_cmd.strsize;295 const size = macho_file.symtab_cmd.stroff + macho_file.symtab_cmd.strsize;
295 const gpa = macho_file.base.comp.gpa;296 const gpa = macho_file.base.comp.gpa;
296 try self.data.resize(gpa, size);297 try self.data.resize(gpa, size);
297 const amt = try macho_file.base.file.?.preadAll(self.data.items, 0);298 const amt = macho_file.base.file.?.preadAll(self.data.items, 0) catch |err|
298 if (amt != size) return error.InputOutput;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", .{});
299}302}
300303
301pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, macho_file: *MachO) error{OutOfMemory}!void {304pub 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 {...@@ -376,7 +379,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {
376 if (atom.getRelocs(macho_file).len == 0) continue;379 if (atom.getRelocs(macho_file).len == 0) continue;
377 // TODO: we will resolve and write ZigObject's TLS data twice:380 // TODO: we will resolve and write ZigObject's TLS data twice:
378 // once here, and once in writeAtoms381 // 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);
380 const code = try gpa.alloc(u8, atom_size);383 const code = try gpa.alloc(u8, atom_size);
381 defer gpa.free(code);384 defer gpa.free(code);
382 self.getAtomData(macho_file, atom.*, code) catch |err| {385 self.getAtomData(macho_file, atom.*, code) catch |err| {
...@@ -400,7 +403,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {...@@ -400,7 +403,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void {
400 has_error = true;403 has_error = true;
401 continue;404 continue;
402 };405 };
403 try macho_file.base.file.?.pwriteAll(code, file_offset);406 try macho_file.pwriteAll(code, file_offset);
404 }407 }
405408
406 if (has_error) return error.ResolveFailed;409 if (has_error) return error.ResolveFailed;
...@@ -419,7 +422,7 @@ pub fn calcNumRelocs(self: *ZigObject, macho_file: *MachO) void {...@@ -419,7 +422,7 @@ pub fn calcNumRelocs(self: *ZigObject, macho_file: *MachO) void {
419 }422 }
420}423}
421424
422pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void {425pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) error{ LinkFailure, OutOfMemory }!void {
423 const gpa = macho_file.base.comp.gpa;426 const gpa = macho_file.base.comp.gpa;
424 const diags = &macho_file.base.comp.link_diags;427 const diags = &macho_file.base.comp.link_diags;
425428
...@@ -432,14 +435,14 @@ pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void {...@@ -432,14 +435,14 @@ pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void {
432 if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue;435 if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue;
433 if (atom.getRelocs(macho_file).len == 0) continue;436 if (atom.getRelocs(macho_file).len == 0) continue;
434 const extra = atom.getExtra(macho_file);437 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);
436 const code = try gpa.alloc(u8, atom_size);439 const code = try gpa.alloc(u8, atom_size);
437 defer gpa.free(code);440 defer gpa.free(code);
438 self.getAtomData(macho_file, atom.*, code) catch |err|441 self.getAtomData(macho_file, atom.*, code) catch |err|
439 return diags.fail("failed to fetch code for '{s}': {s}", .{ atom.getName(macho_file), @errorName(err) });442 return diags.fail("failed to fetch code for '{s}': {s}", .{ atom.getName(macho_file), @errorName(err) });
440 const file_offset = header.offset + atom.value;443 const file_offset = header.offset + atom.value;
441 try atom.writeRelocs(macho_file, code, relocs[extra.rel_out_index..][0..extra.rel_out_count]);444 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);
443 }446 }
444}447}
445448
...@@ -457,8 +460,8 @@ pub fn writeAtomsRelocatable(self: *ZigObject, macho_file: *MachO) !void {...@@ -457,8 +460,8 @@ pub fn writeAtomsRelocatable(self: *ZigObject, macho_file: *MachO) !void {
457 if (sect.isZerofill()) continue;460 if (sect.isZerofill()) continue;
458 if (macho_file.isZigSection(atom.out_n_sect)) continue;461 if (macho_file.isZigSection(atom.out_n_sect)) continue;
459 if (atom.getRelocs(macho_file).len == 0) continue;462 if (atom.getRelocs(macho_file).len == 0) continue;
460 const off = std.math.cast(usize, atom.value) orelse return error.Overflow;463 const off = try macho_file.cast(usize, atom.value);
461 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;464 const size = try macho_file.cast(usize, atom.size);
462 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;465 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;
463 try self.getAtomData(macho_file, atom.*, buffer[off..][0..size]);466 try self.getAtomData(macho_file, atom.*, buffer[off..][0..size]);
464 const relocs = macho_file.sections.items(.relocs)[atom.out_n_sect].items;467 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 {...@@ -480,8 +483,8 @@ pub fn writeAtoms(self: *ZigObject, macho_file: *MachO) !void {
480 const sect = atom.getInputSection(macho_file);483 const sect = atom.getInputSection(macho_file);
481 if (sect.isZerofill()) continue;484 if (sect.isZerofill()) continue;
482 if (macho_file.isZigSection(atom.out_n_sect)) continue;485 if (macho_file.isZigSection(atom.out_n_sect)) continue;
483 const off = std.math.cast(usize, atom.value) orelse return error.Overflow;486 const off = try macho_file.cast(usize, atom.value);
484 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;487 const size = try macho_file.cast(usize, atom.size);
485 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;488 const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items;
486 try self.getAtomData(macho_file, atom.*, buffer[off..][0..size]);489 try self.getAtomData(macho_file, atom.*, buffer[off..][0..size]);
487 try atom.resolveRelocs(macho_file, buffer[off..][0..size]);490 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...@@ -546,7 +549,9 @@ pub fn getInputSection(self: ZigObject, atom: Atom, macho_file: *MachO) macho.se
546 return sect;549 return sect;
547}550}
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
550 // Handle any lazy symbols that were emitted by incremental compilation.555 // Handle any lazy symbols that were emitted by incremental compilation.
551 if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {556 if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
552 const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid);557 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)...@@ -554,24 +559,18 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
554559
555 // Most lazy symbols can be updated on first use, but560 // Most lazy symbols can be updated on first use, but
556 // anyerror needs to wait for everything to be flushed.561 // 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(
558 macho_file,563 macho_file,
559 pt,564 pt,
560 .{ .kind = .code, .ty = .anyerror_type },565 .{ .kind = .code, .ty = .anyerror_type },
561 metadata.text_symbol_index,566 metadata.text_symbol_index,
562 ) catch |err| return switch (err) {567 );
563 error.CodegenFail => error.LinkFailure,568 if (metadata.const_state != .unused) try self.updateLazySymbol(
564 else => |e| e,
565 };
566 if (metadata.const_state != .unused) self.updateLazySymbol(
567 macho_file,569 macho_file,
568 pt,570 pt,
569 .{ .kind = .const_data, .ty = .anyerror_type },571 .{ .kind = .const_data, .ty = .anyerror_type },
570 metadata.const_symbol_index,572 metadata.const_symbol_index,
571 ) catch |err| return switch (err) {573 );
572 error.CodegenFail => error.LinkFailure,
573 else => |e| e,
574 };
575 }574 }
576 for (self.lazy_syms.values()) |*metadata| {575 for (self.lazy_syms.values()) |*metadata| {
577 if (metadata.text_state != .unused) metadata.text_state = .flushed;576 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)...@@ -581,7 +580,11 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
581 if (self.dwarf) |*dwarf| {580 if (self.dwarf) |*dwarf| {
582 const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid);581 const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid);
583 defer pt.deactivate();582 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
586 self.debug_abbrev_dirty = false;589 self.debug_abbrev_dirty = false;
587 self.debug_aranges_dirty = false;590 self.debug_aranges_dirty = false;
...@@ -616,6 +619,7 @@ pub fn getNavVAddr(...@@ -616,6 +619,7 @@ pub fn getNavVAddr(
616 const sym = self.symbols.items[sym_index];619 const sym = self.symbols.items[sym_index];
617 const vaddr = sym.getAddress(.{}, macho_file);620 const vaddr = sym.getAddress(.{}, macho_file);
618 switch (reloc_info.parent) {621 switch (reloc_info.parent) {
622 .none => unreachable,
619 .atom_index => |atom_index| {623 .atom_index => |atom_index| {
620 const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?;624 const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?;
621 try parent_atom.addReloc(macho_file, .{625 try parent_atom.addReloc(macho_file, .{
...@@ -655,6 +659,7 @@ pub fn getUavVAddr(...@@ -655,6 +659,7 @@ pub fn getUavVAddr(
655 const sym = self.symbols.items[sym_index];659 const sym = self.symbols.items[sym_index];
656 const vaddr = sym.getAddress(.{}, macho_file);660 const vaddr = sym.getAddress(.{}, macho_file);
657 switch (reloc_info.parent) {661 switch (reloc_info.parent) {
662 .none => unreachable,
658 .atom_index => |atom_index| {663 .atom_index => |atom_index| {
659 const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?;664 const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?;
660 try parent_atom.addReloc(macho_file, .{665 try parent_atom.addReloc(macho_file, .{
...@@ -766,7 +771,7 @@ pub fn updateFunc(...@@ -766,7 +771,7 @@ pub fn updateFunc(
766 func_index: InternPool.Index,771 func_index: InternPool.Index,
767 air: Air,772 air: Air,
768 liveness: Liveness,773 liveness: Liveness,
769) !void {774) link.File.UpdateNavError!void {
770 const tracy = trace(@src());775 const tracy = trace(@src());
771 defer tracy.end();776 defer tracy.end();
772777
...@@ -936,7 +941,7 @@ fn updateNavCode(...@@ -936,7 +941,7 @@ fn updateNavCode(
936 sym_index: Symbol.Index,941 sym_index: Symbol.Index,
937 sect_index: u8,942 sect_index: u8,
938 code: []const u8,943 code: []const u8,
939) !void {944) link.File.UpdateNavError!void {
940 const zcu = pt.zcu;945 const zcu = pt.zcu;
941 const gpa = zcu.gpa;946 const gpa = zcu.gpa;
942 const ip = &zcu.intern_pool;947 const ip = &zcu.intern_pool;
...@@ -950,6 +955,7 @@ fn updateNavCode(...@@ -950,6 +955,7 @@ fn updateNavCode(
950 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),955 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
951 };956 };
952957
958 const diags = &macho_file.base.comp.link_diags;
953 const sect = &macho_file.sections.items(.header)[sect_index];959 const sect = &macho_file.sections.items(.header)[sect_index];
954 const sym = &self.symbols.items[sym_index];960 const sym = &self.symbols.items[sym_index];
955 const nlist = &self.symtab.items(.nlist)[sym.nlist_idx];961 const nlist = &self.symtab.items(.nlist)[sym.nlist_idx];
...@@ -978,7 +984,7 @@ fn updateNavCode(...@@ -978,7 +984,7 @@ fn updateNavCode(
978 const need_realloc = code.len > capacity or !required_alignment.check(atom.value);984 const need_realloc = code.len > capacity or !required_alignment.check(atom.value);
979985
980 if (need_realloc) {986 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)});
982 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value });988 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value });
983 if (old_vaddr != atom.value) {989 if (old_vaddr != atom.value) {
984 sym.value = 0;990 sym.value = 0;
...@@ -1000,7 +1006,7 @@ fn updateNavCode(...@@ -1000,7 +1006,7 @@ fn updateNavCode(
10001006
1001 if (!sect.isZerofill()) {1007 if (!sect.isZerofill()) {
1002 const file_offset = sect.offset + atom.value;1008 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);
1004 }1010 }
1005}1011}
10061012
...@@ -1236,7 +1242,7 @@ fn lowerConst(...@@ -1236,7 +1242,7 @@ fn lowerConst(
12361242
1237 const sect = macho_file.sections.items(.header)[output_section_index];1243 const sect = macho_file.sections.items(.header)[output_section_index];
1238 const file_offset = sect.offset + atom.value;1244 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
1241 return .{ .ok = sym_index };1247 return .{ .ok = sym_index };
1242}1248}
...@@ -1347,9 +1353,10 @@ fn updateLazySymbol(...@@ -1347,9 +1353,10 @@ fn updateLazySymbol(
1347 pt: Zcu.PerThread,1353 pt: Zcu.PerThread,
1348 lazy_sym: link.File.LazySymbol,1354 lazy_sym: link.File.LazySymbol,
1349 symbol_index: Symbol.Index,1355 symbol_index: Symbol.Index,
1350) !void {1356) error{ OutOfMemory, LinkFailure }!void {
1351 const zcu = pt.zcu;1357 const zcu = pt.zcu;
1352 const gpa = zcu.gpa;1358 const gpa = zcu.gpa;
1359 const diags = &macho_file.base.comp.link_diags;
13531360
1354 var required_alignment: Atom.Alignment = .none;1361 var required_alignment: Atom.Alignment = .none;
1355 var code_buffer = std.ArrayList(u8).init(gpa);1362 var code_buffer = std.ArrayList(u8).init(gpa);
...@@ -1365,7 +1372,7 @@ fn updateLazySymbol(...@@ -1365,7 +1372,7 @@ fn updateLazySymbol(
1365 };1372 };
13661373
1367 const src = Type.fromInterned(lazy_sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded;1374 const src = Type.fromInterned(lazy_sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded;
1368 const res = try codegen.generateLazySymbol(1375 const res = codegen.generateLazySymbol(
1369 &macho_file.base,1376 &macho_file.base,
1370 pt,1377 pt,
1371 src,1378 src,
...@@ -1374,13 +1381,14 @@ fn updateLazySymbol(...@@ -1374,13 +1381,14 @@ fn updateLazySymbol(
1374 &code_buffer,1381 &code_buffer,
1375 .none,1382 .none,
1376 .{ .atom_index = symbol_index },1383 .{ .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 };
1378 const code = switch (res) {1389 const code = switch (res) {
1379 .ok => code_buffer.items,1390 .ok => code_buffer.items,
1380 .fail => |em| {1391 .fail => |em| return diags.fail("codegen failure: {s}", .{em.msg}),
1381 log.err("{s}", .{em.msg});
1382 return error.CodegenFail;
1383 },
1384 };1392 };
13851393
1386 const output_section_index = switch (lazy_sym.kind) {1394 const output_section_index = switch (lazy_sym.kind) {
...@@ -1412,7 +1420,7 @@ fn updateLazySymbol(...@@ -1412,7 +1420,7 @@ fn updateLazySymbol(
14121420
1413 const sect = macho_file.sections.items(.header)[output_section_index];1421 const sect = macho_file.sections.items(.header)[output_section_index];
1414 const file_offset = sect.offset + atom.value;1422 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);
1416}1424}
14171425
1418pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {1426pub 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 {...@@ -1486,7 +1494,7 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, macho_file: *MachO) !void {
1486 .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf),1494 .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf),
1487 else => @panic("TODO implement write trampoline for this CPU arch"),1495 else => @panic("TODO implement write trampoline for this CPU arch"),
1488 };1496 };
1489 try macho_file.base.file.?.pwriteAll(out, fileoff);1497 try macho_file.pwriteAll(out, fileoff);
1490}1498}
14911499
1492pub fn getOrCreateMetadataForNav(1500pub 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...@@ -18,13 +18,15 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
18 // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all18 // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all
19 // debug info segments/sections (this is apparently by design by Apple), we copy19 // debug info segments/sections (this is apparently by design by Apple), we copy
20 // the *only* input file over.20 // 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.
23 const path = positionals.items[0].path().?;21 const path = positionals.items[0].path().?;
24 const in_file = try path.root_dir.handle.openFile(path.sub_path, .{});22 const in_file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err|
25 const stat = try in_file.stat();23 return diags.fail("failed to open {}: {s}", .{ path, @errorName(err) });
26 const amt = try in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size);24 const stat = in_file.stat() catch |err|
27 if (amt != stat.size) return error.InputOutput; // TODO: report an actual user error25 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});
28 return;30 return;
29 }31 }
3032
...@@ -40,7 +42,11 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat...@@ -40,7 +42,11 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
40 if (diags.hasErrors()) return error.LinkFailure;42 if (diags.hasErrors()) return error.LinkFailure;
4143
42 try macho_file.resolveSymbols();44 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 };
44 markExports(macho_file);50 markExports(macho_file);
45 claimUnresolved(macho_file);51 claimUnresolved(macho_file);
46 try initOutputSections(macho_file);52 try initOutputSections(macho_file);
...@@ -108,7 +114,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -108,7 +114,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
108 try macho_file.addAtomsToSections();114 try macho_file.addAtomsToSections();
109 try calcSectionSizes(macho_file);115 try calcSectionSizes(macho_file);
110 try createSegment(macho_file);116 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)});
112 allocateSegment(macho_file);119 allocateSegment(macho_file);
113120
114 if (build_options.enable_logging) {121 if (build_options.enable_logging) {
...@@ -126,8 +133,6 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -126,8 +133,6 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
126 const ncmds, const sizeofcmds = try writeLoadCommands(macho_file);133 const ncmds, const sizeofcmds = try writeLoadCommands(macho_file);
127 try writeHeader(macho_file, ncmds, sizeofcmds);134 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.
131 try zo.readFileContents(macho_file);136 try zo.readFileContents(macho_file);
132 }137 }
133138
...@@ -152,7 +157,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -152,7 +157,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
152157
153 // Update sizes of contributing objects158 // Update sizes of contributing objects
154 for (files.items) |index| {159 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)});
156 }162 }
157163
158 // Update file offsets of contributing objects164 // Update file offsets of contributing objects
...@@ -171,7 +177,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -171,7 +177,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
171 state.file_off = pos;177 state.file_off = pos;
172 pos += @sizeOf(Archive.ar_hdr);178 pos += @sizeOf(Archive.ar_hdr);
173 pos += mem.alignForward(usize, zo.basename.len + 1, ptr_width);179 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);
175 },181 },
176 .object => |o| {182 .object => |o| {
177 const state = &o.output_ar_state;183 const state = &o.output_ar_state;
...@@ -179,7 +185,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -179,7 +185,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
179 state.file_off = pos;185 state.file_off = pos;
180 pos += @sizeOf(Archive.ar_hdr);186 pos += @sizeOf(Archive.ar_hdr);
181 pos += mem.alignForward(usize, o.path.basename().len + 1, ptr_width);187 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);
183 },189 },
184 else => unreachable,190 else => unreachable,
185 }191 }
...@@ -201,7 +207,10 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -201,7 +207,10 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
201 try writer.writeAll(Archive.ARMAG);207 try writer.writeAll(Archive.ARMAG);
202208
203 // Write symtab209 // 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
206 // Write object files215 // Write object files
207 for (files.items) |index| {216 for (files.items) |index| {
...@@ -210,13 +219,14 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -210,13 +219,14 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
210 if (padding > 0) {219 if (padding > 0) {
211 try writer.writeByteNTimes(0, padding);220 try writer.writeByteNTimes(0, padding);
212 }221 }
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)});
214 }224 }
215225
216 assert(buffer.items.len == total_size);226 assert(buffer.items.len == total_size);
217227
218 try macho_file.base.file.?.setEndPos(total_size);228 try macho_file.setEndPos(total_size);
219 try macho_file.base.file.?.pwriteAll(buffer.items, 0);229 try macho_file.pwriteAll(buffer.items, 0);
220230
221 if (diags.hasErrors()) return error.LinkFailure;231 if (diags.hasErrors()) return error.LinkFailure;
222}232}
...@@ -452,11 +462,10 @@ fn allocateSections(macho_file: *MachO) !void {...@@ -452,11 +462,10 @@ fn allocateSections(macho_file: *MachO) !void {
452 for (slice.items(.header)) |*header| {462 for (slice.items(.header)) |*header| {
453 const needed_size = header.size;463 const needed_size = header.size;
454 header.size = 0;464 header.size = 0;
455 const alignment = try math.powi(u32, 2, header.@"align");465 const alignment = try macho_file.alignPow(header.@"align");
456 if (!header.isZerofill()) {466 if (!header.isZerofill()) {
457 if (needed_size > macho_file.allocatedSize(header.offset)) {467 if (needed_size > macho_file.allocatedSize(header.offset)) {
458 header.offset = math.cast(u32, try macho_file.findFreeSpace(needed_size, alignment)) orelse468 header.offset = try macho_file.cast(u32, try macho_file.findFreeSpace(needed_size, alignment));
459 return error.Overflow;
460 }469 }
461 }470 }
462 if (needed_size > macho_file.allocatedSizeVirtual(header.addr)) {471 if (needed_size > macho_file.allocatedSizeVirtual(header.addr)) {
...@@ -572,7 +581,7 @@ fn sortRelocs(macho_file: *MachO) void {...@@ -572,7 +581,7 @@ fn sortRelocs(macho_file: *MachO) void {
572 }581 }
573}582}
574583
575fn writeSections(macho_file: *MachO) !void {584fn writeSections(macho_file: *MachO) link.File.FlushError!void {
576 const tracy = trace(@src());585 const tracy = trace(@src());
577 defer tracy.end();586 defer tracy.end();
578587
...@@ -583,7 +592,7 @@ fn writeSections(macho_file: *MachO) !void {...@@ -583,7 +592,7 @@ fn writeSections(macho_file: *MachO) !void {
583 for (slice.items(.header), slice.items(.out), slice.items(.relocs), 0..) |header, *out, *relocs, n_sect| {592 for (slice.items(.header), slice.items(.out), slice.items(.relocs), 0..) |header, *out, *relocs, n_sect| {
584 if (header.isZerofill()) continue;593 if (header.isZerofill()) continue;
585 if (!macho_file.isZigSection(@intCast(n_sect))) { // TODO this is wrong; what about debug sections?594 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);
587 try out.resize(gpa, size);596 try out.resize(gpa, size);
588 const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0;597 const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0;
589 @memset(out.items, padding_byte);598 @memset(out.items, padding_byte);
...@@ -662,16 +671,16 @@ fn writeSectionsToFile(macho_file: *MachO) !void {...@@ -662,16 +671,16 @@ fn writeSectionsToFile(macho_file: *MachO) !void {
662671
663 const slice = macho_file.sections.slice();672 const slice = macho_file.sections.slice();
664 for (slice.items(.header), slice.items(.out), slice.items(.relocs)) |header, out, relocs| {673 for (slice.items(.header), slice.items(.out), slice.items(.relocs)) |header, out, relocs| {
665 try macho_file.base.file.?.pwriteAll(out.items, header.offset);674 try macho_file.pwriteAll(out.items, header.offset);
666 try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);675 try macho_file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff);
667 }676 }
668677
669 try macho_file.writeDataInCode();678 try macho_file.writeDataInCode();
670 try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff);679 try macho_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);680 try macho_file.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff);
672}681}
673682
674fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {683fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } {
675 const gpa = macho_file.base.comp.gpa;684 const gpa = macho_file.base.comp.gpa;
676 const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file);685 const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file);
677 const buffer = try gpa.alloc(u8, needed_size);686 const buffer = try gpa.alloc(u8, needed_size);
...@@ -686,31 +695,45 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {...@@ -686,31 +695,45 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } {
686 {695 {
687 assert(macho_file.segments.items.len == 1);696 assert(macho_file.segments.items.len == 1);
688 const seg = macho_file.segments.items[0];697 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 };
690 for (macho_file.sections.items(.header)) |header| {701 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 };
692 }705 }
693 ncmds += 1;706 ncmds += 1;
694 }707 }
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 };
697 ncmds += 1;712 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 };
699 ncmds += 1;716 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 };
701 ncmds += 1;720 ncmds += 1;
702721
703 if (macho_file.platform.isBuildVersionCompatible()) {722 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 };
705 ncmds += 1;726 ncmds += 1;
706 } else {727 } 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 };
708 ncmds += 1;731 ncmds += 1;
709 }732 }
710733
711 assert(stream.pos == needed_size);734 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
715 return .{ ncmds, buffer.len };738 return .{ ncmds, buffer.len };
716}739}
...@@ -742,7 +765,7 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {...@@ -742,7 +765,7 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
742 header.ncmds = @intCast(ncmds);765 header.ncmds = @intCast(ncmds);
743 header.sizeofcmds = @intCast(sizeofcmds);766 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);
746}769}
747770
748const std = @import("std");771const std = @import("std");
src/link/Plan9.zig+38-25
...@@ -535,16 +535,21 @@ fn allocateGotIndex(self: *Plan9) usize {...@@ -535,16 +535,21 @@ fn allocateGotIndex(self: *Plan9) usize {
535 }535 }
536}536}
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 {
539 const comp = self.base.comp;544 const comp = self.base.comp;
545 const diags = &comp.link_diags;
540 const use_lld = build_options.have_llvm and comp.config.use_lld;546 const use_lld = build_options.have_llvm and comp.config.use_lld;
541 assert(!use_lld);547 assert(!use_lld);
542548
543 switch (link.File.effectiveOutputMode(use_lld, comp.config.output_mode)) {549 switch (link.File.effectiveOutputMode(use_lld, comp.config.output_mode)) {
544 .Exe => {},550 .Exe => {},
545 // plan9 object files are totally different551 .Obj => return diags.fail("writing plan9 object files unimplemented", .{}),
546 .Obj => return error.TODOImplementPlan9Objs,552 .Lib => return diags.fail("writing plan9 lib files unimplemented", .{}),
547 .Lib => return error.TODOImplementWritingLibFiles,
548 }553 }
549 return self.flushModule(arena, tid, prog_node);554 return self.flushModule(arena, tid, prog_node);
550}555}
...@@ -589,7 +594,13 @@ fn atomCount(self: *Plan9) usize {...@@ -589,7 +594,13 @@ fn atomCount(self: *Plan9) usize {
589 return data_nav_count + fn_nav_count + lazy_atom_count + extern_atom_count + uav_atom_count;594 return data_nav_count + fn_nav_count + lazy_atom_count + extern_atom_count + uav_atom_count;
590}595}
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 {
593 if (build_options.skip_non_native and builtin.object_format != .plan9) {604 if (build_options.skip_non_native and builtin.object_format != .plan9) {
594 @panic("Attempted to compile for object format that was disabled by build configuration");605 @panic("Attempted to compile for object format that was disabled by build configuration");
595 }606 }
...@@ -600,6 +611,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -600,6 +611,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
600 _ = arena; // Has the same lifetime as the call to Compilation.update.611 _ = arena; // Has the same lifetime as the call to Compilation.update.
601612
602 const comp = self.base.comp;613 const comp = self.base.comp;
614 const diags = &comp.link_diags;
603 const gpa = comp.gpa;615 const gpa = comp.gpa;
604 const target = comp.root_mod.resolved_target.result;616 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...@@ -611,7 +623,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
611 defer assert(self.hdr.entry != 0x0);623 defer assert(self.hdr.entry != 0x0);
612624
613 const pt: Zcu.PerThread = .activate(625 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", .{}),
615 tid,627 tid,
616 );628 );
617 defer pt.deactivate();629 defer pt.deactivate();
...@@ -620,22 +632,16 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -620,22 +632,16 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
620 if (self.lazy_syms.getPtr(.none)) |metadata| {632 if (self.lazy_syms.getPtr(.none)) |metadata| {
621 // Most lazy symbols can be updated on first use, but633 // Most lazy symbols can be updated on first use, but
622 // anyerror needs to wait for everything to be flushed.634 // 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(
624 pt,636 pt,
625 .{ .kind = .code, .ty = .anyerror_type },637 .{ .kind = .code, .ty = .anyerror_type },
626 metadata.text_atom,638 metadata.text_atom,
627 ) catch |err| return switch (err) {639 );
628 error.CodegenFail => error.LinkFailure,640 if (metadata.rodata_state != .unused) try self.updateLazySymbolAtom(
629 else => |e| e,
630 };
631 if (metadata.rodata_state != .unused) self.updateLazySymbolAtom(
632 pt,641 pt,
633 .{ .kind = .const_data, .ty = .anyerror_type },642 .{ .kind = .const_data, .ty = .anyerror_type },
634 metadata.rodata_atom,643 metadata.rodata_atom,
635 ) catch |err| return switch (err) {644 );
636 error.CodegenFail => error.LinkFailure,
637 else => |e| e,
638 };
639 }645 }
640 for (self.lazy_syms.values()) |*metadata| {646 for (self.lazy_syms.values()) |*metadata| {
641 if (metadata.text_state != .unused) metadata.text_state = .flushed;647 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...@@ -908,8 +914,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
908 }914 }
909 }915 }
910 }916 }
911 // write it all!917 file.pwritevAll(iovecs, 0) catch |err| return diags.fail("failed to write file: {s}", .{@errorName(err)});
912 try file.pwritevAll(iovecs, 0);
913}918}
914fn addNavExports(919fn addNavExports(
915 self: *Plan9,920 self: *Plan9,
...@@ -1047,8 +1052,15 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, pt: Zcu.PerThread, lazy_sym: F...@@ -1047,8 +1052,15 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, pt: Zcu.PerThread, lazy_sym: F
1047 return atom;1052 return atom;
1048}1053}
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 {
1051 const gpa = pt.zcu.gpa;1061 const gpa = pt.zcu.gpa;
1062 const comp = self.base.comp;
1063 const diags = &comp.link_diags;
10521064
1053 var required_alignment: InternPool.Alignment = .none;1065 var required_alignment: InternPool.Alignment = .none;
1054 var code_buffer = std.ArrayList(u8).init(gpa);1066 var code_buffer = std.ArrayList(u8).init(gpa);
...@@ -1069,7 +1081,7 @@ fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, a...@@ -1069,7 +1081,7 @@ fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, a
10691081
1070 // generate the code1082 // generate the code
1071 const src = Type.fromInterned(sym.ty).srcLocOrNull(pt.zcu) orelse Zcu.LazySrcLoc.unneeded;1083 const src = Type.fromInterned(sym.ty).srcLocOrNull(pt.zcu) orelse Zcu.LazySrcLoc.unneeded;
1072 const res = try codegen.generateLazySymbol(1084 const res = codegen.generateLazySymbol(
1073 &self.base,1085 &self.base,
1074 pt,1086 pt,
1075 src,1087 src,
...@@ -1078,13 +1090,14 @@ fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, a...@@ -1078,13 +1090,14 @@ fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, a
1078 &code_buffer,1090 &code_buffer,
1079 .none,1091 .none,
1080 .{ .atom_index = @intCast(atom_index) },1092 .{ .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 };
1082 const code = switch (res) {1098 const code = switch (res) {
1083 .ok => code_buffer.items,1099 .ok => code_buffer.items,
1084 .fail => |em| {1100 .fail => |em| return diags.fail("codegen failure: {s}", .{em.msg}),
1085 log.err("{s}", .{em.msg});
1086 return error.CodegenFail;
1087 },
1088 };1101 };
1089 // duped_code is freed when the atom is freed1102 // duped_code is freed when the atom is freed
1090 const duped_code = try gpa.dupe(u8, code);1103 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...@@ -206,7 +206,17 @@ pub fn flush(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
206 return self.flushModule(arena, tid, prog_node);206 return self.flushModule(arena, tid, prog_node);
207}207}
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
210 if (build_options.skip_non_native) {220 if (build_options.skip_non_native) {
211 @panic("Attempted to compile for architecture that was disabled by build configuration");221 @panic("Attempted to compile for architecture that was disabled by build configuration");
212 }222 }
...@@ -217,12 +227,11 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -217,12 +227,11 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
217 const sub_prog_node = prog_node.start("Flush Module", 0);227 const sub_prog_node = prog_node.start("Flush Module", 0);
218 defer sub_prog_node.end();228 defer sub_prog_node.end();
219229
220 const spv = &self.object.spv;
221
222 const comp = self.base.comp;230 const comp = self.base.comp;
231 const spv = &self.object.spv;
232 const diags = &comp.link_diags;
223 const gpa = comp.gpa;233 const gpa = comp.gpa;
224 const target = comp.getTarget();234 const target = comp.getTarget();
225 _ = tid;
226235
227 try writeCapabilities(spv, target);236 try writeCapabilities(spv, target);
228 try writeMemoryModel(spv, target);237 try writeMemoryModel(spv, target);
...@@ -265,13 +274,11 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -265,13 +274,11 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
265274
266 const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) {275 const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) {
267 error.OutOfMemory => return error.OutOfMemory,276 error.OutOfMemory => return error.OutOfMemory,
268 else => |other| {277 else => |other| return diags.fail("error while linking: {s}", .{@errorName(other)}),
269 log.err("error while linking: {s}", .{@errorName(other)});
270 return error.LinkFailure;
271 },
272 };278 };
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)});
275}282}
276283
277fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: std.Progress.Node) ![]Word {284fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: std.Progress.Node) ![]Word {
src/link/Wasm.zig+137-25
...@@ -1,3 +1,14 @@...@@ -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
1const Wasm = @This();12const Wasm = @This();
2const Archive = @import("Wasm/Archive.zig");13const Archive = @import("Wasm/Archive.zig");
3const Object = @import("Wasm/Object.zig");14const Object = @import("Wasm/Object.zig");
...@@ -164,10 +175,12 @@ functions: std.AutoArrayHashMapUnmanaged(FunctionImport.Resolution, void) = .emp...@@ -164,10 +175,12 @@ functions: std.AutoArrayHashMapUnmanaged(FunctionImport.Resolution, void) = .emp
164functions_len: u32 = 0,175functions_len: u32 = 0,
165/// Immutable after prelink. The undefined functions coming only from all object files.176/// Immutable after prelink. The undefined functions coming only from all object files.
166/// The Zcu must satisfy these.177/// The Zcu must satisfy these.
167function_imports_init: []FunctionImportId = &.{},178function_imports_init_keys: []String = &.{},
168/// Initialized as copy of `function_imports_init`; entries are deleted as179function_imports_init_vals: []FunctionImportId = &.{},
169/// they are satisfied by the Zcu.180/// Initialized as copy of `function_imports_init_keys` and
170function_imports: std.AutoArrayHashMapUnmanaged(FunctionImportId, void) = .empty,181/// `function_import_init_vals`; entries are deleted as they are satisfied by
182/// the Zcu.
183function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImportId) = .empty,
171184
172/// Ordered list of non-import globals that will appear in the final binary.185/// Ordered list of non-import globals that will appear in the final binary.
173/// Empty until prelink.186/// Empty until prelink.
...@@ -175,38 +188,53 @@ globals: std.AutoArrayHashMapUnmanaged(GlobalImport.Resolution, void) = .empty,...@@ -175,38 +188,53 @@ globals: std.AutoArrayHashMapUnmanaged(GlobalImport.Resolution, void) = .empty,
175/// Tracks the value at the end of prelink, at which point `globals`188/// Tracks the value at the end of prelink, at which point `globals`
176/// contains only object file globals, and nothing from the Zcu yet.189/// contains only object file globals, and nothing from the Zcu yet.
177globals_len: u32 = 0,190globals_len: u32 = 0,
178global_imports_init: []GlobalImportId = &.{},191global_imports_init_keys: []String = &.{},
179global_imports: std.AutoArrayHashMapUnmanaged(GlobalImportId, void) = .empty,192global_imports_init_vals: []GlobalImportId = &.{},
193global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImportId) = .empty,
180194
181/// Ordered list of non-import tables that will appear in the final binary.195/// Ordered list of non-import tables that will appear in the final binary.
182/// Empty until prelink.196/// Empty until prelink.
183tables: std.AutoArrayHashMapUnmanaged(TableImport.Resolution, void) = .empty,197tables: std.AutoArrayHashMapUnmanaged(TableImport.Resolution, void) = .empty,
184table_imports: std.AutoArrayHashMapUnmanaged(ObjectTableImportIndex, void) = .empty,198table_imports: std.AutoArrayHashMapUnmanaged(String, ObjectTableImportIndex) = .empty,
185199
186any_exports_updated: bool = true,200any_exports_updated: bool = true,
187201
202/// Index into `objects`.
203pub const ObjectIndex = enum(u32) {
204 _,
205};
206
188/// Index into `functions`.207/// Index into `functions`.
189pub const FunctionIndex = enum(u32) {208pub const FunctionIndex = enum(u32) {
190 _,209 _,
191210
192 pub fn fromNav(nav_index: InternPool.Nav.Index, wasm: *const Wasm) FunctionIndex {211 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?FunctionIndex {
193 return @enumFromInt(wasm.functions.getIndex(.pack(wasm, .{ .nav = nav_index })).?);212 const i = wasm.functions.getIndex(.fromIpNav(wasm, nav_index)) orelse return null;
213 return @enumFromInt(i);
194 }214 }
195};215};
196216
197/// 0. Index into `function_imports`217/// 0. Index into `function_imports`
198/// 1. Index into `functions`.218/// 1. Index into `functions`.
219///
220/// Note that function_imports indexes are subject to swap removals during
221/// `flush`.
199pub const OutputFunctionIndex = enum(u32) {222pub const OutputFunctionIndex = enum(u32) {
200 _,223 _,
201};224};
202225
203/// Index into `globals`.226/// Index into `globals`.
204const GlobalIndex = enum(u32) {227pub const GlobalIndex = enum(u32) {
205 _,228 _,
206229
207 fn key(index: GlobalIndex, f: *const Flush) *Wasm.GlobalImport.Resolution {230 fn key(index: GlobalIndex, f: *const Flush) *Wasm.GlobalImport.Resolution {
208 return &f.globals.items[@intFromEnum(index)];231 return &f.globals.items[@intFromEnum(index)];
209 }232 }
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 }
210};238};
211239
212/// The first N indexes correspond to input objects (`objects`) array.240/// The first N indexes correspond to input objects (`objects`) array.
...@@ -218,6 +246,38 @@ pub const SourceLocation = enum(u32) {...@@ -218,6 +246,38 @@ pub const SourceLocation = enum(u32) {
218 zig_object_nofile = std.math.maxInt(u32) - 1,246 zig_object_nofile = std.math.maxInt(u32) - 1,
219 none = std.math.maxInt(u32),247 none = std.math.maxInt(u32),
220 _,248 _,
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 }
221};281};
222282
223/// The lower bits of this ABI-match the flags here:283/// The lower bits of this ABI-match the flags here:
...@@ -445,6 +505,10 @@ pub const FunctionImport = extern struct {...@@ -445,6 +505,10 @@ pub const FunctionImport = extern struct {
445 };505 };
446 }506 }
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
448 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {512 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {
449 return switch (r.unpack(wasm)) {513 return switch (r.unpack(wasm)) {
450 .unresolved, .nav => true,514 .unresolved, .nav => true,
...@@ -587,6 +651,10 @@ pub const ObjectGlobalImportIndex = enum(u32) {...@@ -587,6 +651,10 @@ pub const ObjectGlobalImportIndex = enum(u32) {
587/// Index into `object_table_imports`.651/// Index into `object_table_imports`.
588pub const ObjectTableImportIndex = enum(u32) {652pub const ObjectTableImportIndex = enum(u32) {
589 _,653 _,
654
655 pub fn ptr(index: ObjectTableImportIndex, wasm: *const Wasm) *TableImport {
656 return &wasm.object_table_imports.items[@intFromEnum(index)];
657 }
590};658};
591659
592/// Index into `object_tables`.660/// Index into `object_tables`.
...@@ -797,12 +865,48 @@ pub const ValtypeList = enum(u32) {...@@ -797,12 +865,48 @@ pub const ValtypeList = enum(u32) {
797/// 1. Index into `imports`.865/// 1. Index into `imports`.
798pub const FunctionImportId = enum(u32) {866pub const FunctionImportId = enum(u32) {
799 _,867 _,
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 }
800};886};
801887
802/// 0. Index into `object_global_imports`.888/// 0. Index into `object_global_imports`.
803/// 1. Index into `imports`.889/// 1. Index into `imports`.
804pub const GlobalImportId = enum(u32) {890pub const GlobalImportId = enum(u32) {
805 _,891 _,
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 }
806};910};
807911
808pub const Relocation = struct {912pub const Relocation = struct {
...@@ -897,7 +1001,7 @@ pub const InitFunc = extern struct {...@@ -897,7 +1001,7 @@ pub const InitFunc = extern struct {
897 priority: u32,1001 priority: u32,
898 function_index: ObjectFunctionIndex,1002 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 {
901 _ = ctx;1005 _ = ctx;
902 if (lhs.priority == rhs.priority) {1006 if (lhs.priority == rhs.priority) {
903 return @intFromEnum(lhs.function_index) < @intFromEnum(rhs.function_index);1007 return @intFromEnum(lhs.function_index) < @intFromEnum(rhs.function_index);
...@@ -1237,18 +1341,19 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1237,18 +1341,19 @@ pub fn deinit(wasm: *Wasm) void {
1237 wasm.object_comdat_symbols.deinit(gpa);1341 wasm.object_comdat_symbols.deinit(gpa);
1238 wasm.objects.deinit(gpa);1342 wasm.objects.deinit(gpa);
12391343
1240 wasm.atoms.deinit(gpa);
1241
1242 wasm.synthetic_symbols.deinit(gpa);1344 wasm.synthetic_symbols.deinit(gpa);
1243 wasm.globals.deinit(gpa);
1244 wasm.undefs.deinit(gpa);1345 wasm.undefs.deinit(gpa);
1245 wasm.discarded.deinit(gpa);1346 wasm.discarded.deinit(gpa);
1246 wasm.segments.deinit(gpa);1347 wasm.segments.deinit(gpa);
1247 wasm.segment_info.deinit(gpa);1348 wasm.segment_info.deinit(gpa);
12481349
1249 wasm.global_imports.deinit(gpa);
1250 wasm.func_types.deinit(gpa);1350 wasm.func_types.deinit(gpa);
1351 wasm.function_exports.deinit(gpa);
1352 wasm.function_imports.deinit(gpa);
1251 wasm.functions.deinit(gpa);1353 wasm.functions.deinit(gpa);
1354 wasm.globals.deinit(gpa);
1355 wasm.global_imports.deinit(gpa);
1356 wasm.table_imports.deinit(gpa);
1252 wasm.output_globals.deinit(gpa);1357 wasm.output_globals.deinit(gpa);
1253 wasm.exports.deinit(gpa);1358 wasm.exports.deinit(gpa);
12541359
...@@ -1340,13 +1445,19 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index...@@ -1340,13 +1445,19 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
13401445
1341 if (!nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {1446 if (!nav_init.typeOf(zcu).hasRuntimeBits(zcu)) {
1342 _ = wasm.imports.swapRemove(nav_index);1447 _ = wasm.imports.swapRemove(nav_index);
1343 _ = wasm.navs.swapRemove(nav_index); // TODO reclaim resources1448 if (wasm.navs.swapRemove(nav_index)) |old| {
1449 _ = old;
1450 @panic("TODO reclaim resources");
1451 }
1344 return;1452 return;
1345 }1453 }
13461454
1347 if (is_extern) {1455 if (is_extern) {
1348 try wasm.imports.put(nav_index, {});1456 try wasm.imports.put(nav_index, {});
1349 _ = wasm.navs.swapRemove(nav_index); // TODO reclaim resources1457 if (wasm.navs.swapRemove(nav_index)) |old| {
1458 _ = old;
1459 @panic("TODO reclaim resources");
1460 }
1350 return;1461 return;
1351 }1462 }
13521463
...@@ -1528,7 +1639,8 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -1528,7 +1639,8 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
1528 }1639 }
1529 }1640 }
1530 wasm.functions_len = @intCast(wasm.functions.items.len);1641 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());
1532 wasm.function_exports_len = @intCast(wasm.function_exports.items.len);1644 wasm.function_exports_len = @intCast(wasm.function_exports.items.len);
15331645
1534 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {1646 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...@@ -1538,12 +1650,13 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
1538 }1650 }
1539 }1651 }
1540 wasm.globals_len = @intCast(wasm.globals.items.len);1652 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());
1542 wasm.global_exports_len = @intCast(wasm.global_exports.items.len);1655 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| {
1545 if (import.flags.isIncluded(rdynamic)) {1658 if (import.flags.isIncluded(rdynamic)) {
1546 try markTable(wasm, name, import, @enumFromInt(i));1659 try markTable(wasm, import.name, import, @enumFromInt(i));
1547 continue;1660 continue;
1548 }1661 }
1549 }1662 }
...@@ -1581,7 +1694,7 @@ fn markFunction(...@@ -1581,7 +1694,7 @@ fn markFunction(
1581 import.resolution = .__wasm_init_tls;1694 import.resolution = .__wasm_init_tls;
1582 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});1695 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});
1583 } else {1696 } else {
1584 try wasm.function_imports.put(gpa, .fromObject(func_index), {});1697 try wasm.function_imports.put(gpa, name, .fromObject(func_index));
1585 }1698 }
1586 } else {1699 } else {
1587 const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);1700 const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);
...@@ -1631,7 +1744,7 @@ fn markGlobal(...@@ -1631,7 +1744,7 @@ fn markGlobal(
1631 import.resolution = .__tls_size;1744 import.resolution = .__tls_size;
1632 wasm.globals.putAssumeCapacity(.__tls_size, {});1745 wasm.globals.putAssumeCapacity(.__tls_size, {});
1633 } else {1746 } else {
1634 try wasm.global_imports.put(gpa, .fromObject(global_index), {});1747 try wasm.global_imports.put(gpa, name, .fromObject(global_index));
1635 }1748 }
1636 } else {1749 } else {
1637 const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);1750 const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);
...@@ -1663,7 +1776,7 @@ fn markTable(...@@ -1663,7 +1776,7 @@ fn markTable(
1663 import.resolution = .__indirect_function_table;1776 import.resolution = .__indirect_function_table;
1664 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});1777 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});
1665 } else {1778 } else {
1666 try wasm.table_imports.put(gpa, .fromObject(table_index), {});1779 try wasm.table_imports.put(gpa, name, .fromObject(table_index));
1667 }1780 }
1668 } else {1781 } else {
1669 wasm.tables.putAssumeCapacity(import.resolution, {});1782 wasm.tables.putAssumeCapacity(import.resolution, {});
...@@ -1722,7 +1835,6 @@ pub fn flushModule(...@@ -1722,7 +1835,6 @@ pub fn flushModule(
1722 defer sub_prog_node.end();1835 defer sub_prog_node.end();
17231836
1724 wasm.flush_buffer.clear();1837 wasm.flush_buffer.clear();
1725 defer wasm.flush_buffer.subsequent = true;
1726 return wasm.flush_buffer.finish(wasm, arena);1838 return wasm.flush_buffer.finish(wasm, arena);
1727}1839}
17281840
src/link/Wasm/Flush.zig+32-35
...@@ -39,27 +39,17 @@ const DataSegmentIndex = enum(u32) {...@@ -39,27 +39,17 @@ const DataSegmentIndex = enum(u32) {
3939
40pub fn clear(f: *Flush) void {40pub fn clear(f: *Flush) void {
41 f.binary_bytes.clearRetainingCapacity();41 f.binary_bytes.clearRetainingCapacity();
42 f.function_imports.clearRetainingCapacity();
43 f.global_imports.clearRetainingCapacity();
44 f.functions.clearRetainingCapacity();
45 f.globals.clearRetainingCapacity();
46 f.data_segments.clearRetainingCapacity();42 f.data_segments.clearRetainingCapacity();
47 f.data_segment_groups.clearRetainingCapacity();43 f.data_segment_groups.clearRetainingCapacity();
48 f.indirect_function_table.clearRetainingCapacity();44 f.indirect_function_table.clearRetainingCapacity();
49 f.function_exports.clearRetainingCapacity();
50 f.global_exports.clearRetainingCapacity();45 f.global_exports.clearRetainingCapacity();
51}46}
5247
53pub fn deinit(f: *Flush, gpa: Allocator) void {48pub fn deinit(f: *Flush, gpa: Allocator) void {
54 f.binary_bytes.deinit(gpa);49 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);
59 f.data_segments.deinit(gpa);50 f.data_segments.deinit(gpa);
60 f.data_segment_groups.deinit(gpa);51 f.data_segment_groups.deinit(gpa);
61 f.indirect_function_table.deinit(gpa);52 f.indirect_function_table.deinit(gpa);
62 f.function_exports.deinit(gpa);
63 f.global_exports.deinit(gpa);53 f.global_exports.deinit(gpa);
64 f.* = undefined;54 f.* = undefined;
65}55}
...@@ -79,28 +69,32 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -79,28 +69,32 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
7969
80 if (wasm.any_exports_updated) {70 if (wasm.any_exports_updated) {
81 wasm.any_exports_updated = false;71 wasm.any_exports_updated = false;
72
82 wasm.function_exports.shrinkRetainingCapacity(wasm.function_exports_len);73 wasm.function_exports.shrinkRetainingCapacity(wasm.function_exports_len);
83 wasm.global_exports.shrinkRetainingCapacity(wasm.global_exports_len);74 wasm.global_exports.shrinkRetainingCapacity(wasm.global_exports_len);
8475
85 const entry_name = if (wasm.entry_resolution.isNavOrUnresolved(wasm)) wasm.entry_name else .none;76 const entry_name = if (wasm.entry_resolution.isNavOrUnresolved(wasm)) wasm.entry_name else .none;
8677
87 try f.missing_exports.reinit(gpa, wasm.missing_exports_init, &.{});78 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
88 for (wasm.nav_exports.keys()) |*nav_export| {82 for (wasm.nav_exports.keys()) |*nav_export| {
89 if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) {83 if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) {
90 try wasm.function_exports.append(gpa, .fromNav(nav_export.nav_index, wasm));84 try wasm.function_exports.append(gpa, Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?);
91 if (nav_export.name.toOptional() == entry_name) {85 _ = f.missing_exports.swapRemove(nav_export.name);
92 wasm.entry_resolution = .pack(wasm, .{ .nav = nav_export.nav_index });86 _ = wasm.function_imports.swapRemove(nav_export.name);
93 } else {87
94 f.missing_exports.swapRemove(nav_export.name);88 if (nav_export.name.toOptional() == entry_name)
95 }89 wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index);
96 } else {90 } else {
97 try wasm.global_exports.append(gpa, .fromNav(nav_export.nav_index));91 try wasm.global_exports.append(gpa, Wasm.GlobalIndex.fromIpNav(wasm, nav_export.nav_index).?);
98 f.missing_exports.swapRemove(nav_export.name);92 _ = f.missing_exports.swapRemove(nav_export.name);
93 _ = wasm.global_imports.swapRemove(nav_export.name);
99 }94 }
100 }95 }
10196
102 for (f.missing_exports.keys()) |exp_name| {97 for (f.missing_exports.keys()) |exp_name| {
103 if (exp_name != .none) continue;
104 diags.addError("manually specified export name '{s}' undefined", .{exp_name.slice(wasm)});98 diags.addError("manually specified export name '{s}' undefined", .{exp_name.slice(wasm)});
105 }99 }
106100
...@@ -112,28 +106,31 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -112,28 +106,31 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
112 }106 }
113107
114 if (!allow_undefined) {108 if (!allow_undefined) {
115 for (wasm.function_imports.keys()) |function_import_id| {109 for (wasm.function_imports.keys(), wasm.function_imports.values()) |name, function_import_id| {
116 const name, const src_loc = function_import_id.nameAndLoc(wasm);110 const src_loc = function_import_id.sourceLocation(wasm);
117 diags.addSrcError(src_loc, "undefined function: {s}", .{name.slice(wasm)});111 src_loc.addError(wasm, "undefined function: {s}", .{name.slice(wasm)});
118 }112 }
119 for (wasm.global_imports.keys()) |global_import_id| {113 for (wasm.global_imports.keys(), wasm.global_imports.values()) |name, global_import_id| {
120 const name, const src_loc = global_import_id.nameAndLoc(wasm);114 const src_loc = global_import_id.sourceLocation(wasm);
121 diags.addSrcError(src_loc, "undefined global: {s}", .{name.slice(wasm)});115 src_loc.addError(wasm, "undefined global: {s}", .{name.slice(wasm)});
122 }116 }
123 for (wasm.table_imports.keys()) |table_import_id| {117 for (wasm.table_imports.keys(), wasm.table_imports.values()) |name, table_import_id| {
124 const name, const src_loc = table_import_id.nameAndLoc(wasm);118 const src_loc = table_import_id.ptr(wasm).source_location;
125 diags.addSrcError(src_loc, "undefined table: {s}", .{name.slice(wasm)});119 src_loc.addError(wasm, "undefined table: {s}", .{name.slice(wasm)});
126 }120 }
127 }121 }
128122
129 if (diags.hasErrors()) return error.LinkFailure;123 if (diags.hasErrors()) return error.LinkFailure;
130124
125 wasm.functions.shrinkRetainingCapacity(wasm.functions_len);
126 wasm.globals.shrinkRetainingCapacity(wasm.globals_len);
127
131 // TODO only include init functions for objects with must_link=true or128 // TODO only include init functions for objects with must_link=true or
132 // which have any alive functions inside them.129 // which have any alive functions inside them.
133 if (wasm.object_init_funcs.items.len > 0) {130 if (wasm.object_init_funcs.items.len > 0) {
134 // Zig has no constructors so these are only for object file inputs.131 // Zig has no constructors so these are only for object file inputs.
135 mem.sortUnstable(Wasm.InitFunc, wasm.object_init_funcs.items, {}, Wasm.InitFunc.lessThan);132 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, {});
137 }134 }
138135
139 var any_passive_inits = false;136 var any_passive_inits = false;
...@@ -149,7 +146,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -149,7 +146,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
149 });146 });
150 }147 }
151148
152 try f.functions.ensureUnusedCapacity(gpa, 3);149 try wasm.functions.ensureUnusedCapacity(gpa, 3);
153150
154 // Passive segments are used to avoid memory being reinitialized on each151 // Passive segments are used to avoid memory being reinitialized on each
155 // thread's instantiation. These passive segments are initialized and152 // thread's instantiation. These passive segments are initialized and
...@@ -157,14 +154,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -157,14 +154,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
157 // We also initialize bss segments (using memory.fill) as part of this154 // We also initialize bss segments (using memory.fill) as part of this
158 // function.155 // function.
159 if (any_passive_inits) {156 if (any_passive_inits) {
160 f.functions.putAssumeCapacity(.__wasm_init_memory, {});157 wasm.functions.putAssumeCapacity(.__wasm_init_memory, {});
161 }158 }
162159
163 // When we have TLS GOT entries and shared memory is enabled,160 // When we have TLS GOT entries and shared memory is enabled,
164 // we must perform runtime relocations or else we don't create the function.161 // we must perform runtime relocations or else we don't create the function.
165 if (shared_memory) {162 if (shared_memory) {
166 if (f.need_tls_relocs) f.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {});163 if (f.need_tls_relocs) wasm.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {});
167 f.functions.putAssumeCapacity(gpa, .__wasm_init_tls, {});164 wasm.functions.putAssumeCapacity(gpa, .__wasm_init_tls, {});
168 }165 }
169166
170 // Sort order:167 // Sort order:
...@@ -611,11 +608,11 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {...@@ -611,11 +608,11 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void {
611 }608 }
612609
613 // Code section.610 // Code section.
614 if (f.functions.count() != 0) {611 if (wasm.functions.count() != 0) {
615 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);612 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
616 const start_offset = binary_bytes.items.len - 5; // minus 5 so start offset is 5 to include entry count613 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()) {
619 .unresolved => unreachable,616 .unresolved => unreachable,
620 .__wasm_apply_global_tls_relocs => @panic("TODO lower __wasm_apply_global_tls_relocs"),617 .__wasm_apply_global_tls_relocs => @panic("TODO lower __wasm_apply_global_tls_relocs"),
621 .__wasm_call_ctors => @panic("TODO lower __wasm_call_ctors"),618 .__wasm_call_ctors => @panic("TODO lower __wasm_call_ctors"),
src/link/Wasm/Object.zig+25-15
...@@ -26,12 +26,14 @@ start_function: Wasm.OptionalObjectFunctionIndex,...@@ -26,12 +26,14 @@ start_function: Wasm.OptionalObjectFunctionIndex,
26/// (or therefore missing) and must generate an error when another object uses26/// (or therefore missing) and must generate an error when another object uses
27/// features that are not supported by the other.27/// features that are not supported by the other.
28features: Wasm.Feature.Set,28features: Wasm.Feature.Set,
29/// Points into Wasm functions29/// Points into Wasm object_functions
30functions: RelativeSlice,30functions: RelativeSlice,
31/// Points into Wasm object_globals_imports31/// Points into Wasm object_function_imports
32globals_imports: RelativeSlice,32function_imports: RelativeSlice,
33/// Points into Wasm object_tables_imports33/// Points into Wasm object_global_imports
34tables_imports: RelativeSlice,34global_imports: RelativeSlice,
35/// Points into Wasm object_table_imports
36table_imports: RelativeSlice,
35/// Points into Wasm object_custom_segments37/// Points into Wasm object_custom_segments
36custom_segments: RelativeSlice,38custom_segments: RelativeSlice,
37/// For calculating local section index from `Wasm.SectionIndex`.39/// For calculating local section index from `Wasm.SectionIndex`.
...@@ -180,13 +182,13 @@ fn parse(...@@ -180,13 +182,13 @@ fn parse(
180182
181 const data_segment_start: u32 = @intCast(wasm.object_data_segments.items.len);183 const data_segment_start: u32 = @intCast(wasm.object_data_segments.items.len);
182 const custom_segment_start: u32 = @intCast(wasm.object_custom_segments.items.len);184 const custom_segment_start: u32 = @intCast(wasm.object_custom_segments.items.len);
183 const imports_start: u32 = @intCast(wasm.object_imports.items.len);
184 const functions_start: u32 = @intCast(wasm.object_functions.items.len);185 const functions_start: u32 = @intCast(wasm.object_functions.items.len);
185 const tables_start: u32 = @intCast(wasm.object_tables.items.len);186 const tables_start: u32 = @intCast(wasm.object_tables.items.len);
186 const memories_start: u32 = @intCast(wasm.object_memories.items.len);187 const memories_start: u32 = @intCast(wasm.object_memories.items.len);
187 const globals_start: u32 = @intCast(wasm.object_globals.items.len);188 const globals_start: u32 = @intCast(wasm.object_globals.items.len);
188 const init_funcs_start: u32 = @intCast(wasm.object_init_funcs.items.len);189 const init_funcs_start: u32 = @intCast(wasm.object_init_funcs.items.len);
189 const comdats_start: u32 = @intCast(wasm.object_comdats.items.len);190 const comdats_start: u32 = @intCast(wasm.object_comdats.items.len);
191 const function_imports_start: u32 = @intCast(wasm.object_function_imports.items.len);
190 const global_imports_start: u32 = @intCast(wasm.object_global_imports.items.len);192 const global_imports_start: u32 = @intCast(wasm.object_global_imports.items.len);
191 const table_imports_start: u32 = @intCast(wasm.object_table_imports.items.len);193 const table_imports_start: u32 = @intCast(wasm.object_table_imports.items.len);
192 const local_section_index_base = wasm.object_total_sections;194 const local_section_index_base = wasm.object_total_sections;
...@@ -504,7 +506,7 @@ fn parse(...@@ -504,7 +506,7 @@ fn parse(
504 switch (kind) {506 switch (kind) {
505 .function => {507 .function => {
506 const function, pos = readLeb(u32, bytes, pos);508 const function, pos = readLeb(u32, bytes, pos);
507 try ss.function_imports.append(gpa, .{509 try ss.func_imports.append(gpa, .{
508 .module_name = interned_module_name,510 .module_name = interned_module_name,
509 .name = interned_name,511 .name = interned_name,
510 .index = function,512 .index = function,
...@@ -854,13 +856,13 @@ fn parse(...@@ -854,13 +856,13 @@ fn parse(
854 .archive_member_name = archive_member_name,856 .archive_member_name = archive_member_name,
855 .start_function = start_function,857 .start_function = start_function,
856 .features = features,858 .features = features,
857 .imports = .{
858 .off = imports_start,
859 .len = @intCast(wasm.object_imports.items.len - imports_start),
860 },
861 .functions = .{859 .functions = .{
862 .off = functions_start,860 .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),
864 },866 },
865 .tables = .{867 .tables = .{
866 .off = tables_start,868 .off = tables_start,
...@@ -870,9 +872,17 @@ fn parse(...@@ -870,9 +872,17 @@ fn parse(
870 .off = memories_start,872 .off = memories_start,
871 .len = @intCast(wasm.object_memories.items.len - memories_start),873 .len = @intCast(wasm.object_memories.items.len - memories_start),
872 },874 },
873 .globals = .{875 .function_imports = .{
874 .off = globals_start,876 .off = function_imports_start,
875 .len = @intCast(wasm.object_globals.items.len - globals_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),
876 },886 },
877 .init_funcs = .{887 .init_funcs = .{
878 .off = init_funcs_start,888 .off = init_funcs_start,