| author | |
| committer | |
| log | 16180f525a966de10b6fc0822fea107baf1f24f6 |
| tree | 86a195c2e0cbfc37016aa1f4a4d42fcd425d687e |
| parent | 795e7c64d5f67006246d172e5cd58233cb76f05e |
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 | 1728 | error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)), |
| 1729 | 1729 | error.LinkFailure => assert(comp.link_diags.hasErrors()), |
| 1730 | 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 | 1732 | gpa, |
| 1733 | 1733 | zcu.navSrcLoc(nav_index), |
| 1734 | 1734 | "unable to codegen: {s}", |
| ... | ... | @@ -3114,7 +3114,7 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error |
| 3114 | 3114 | error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)), |
| 3115 | 3115 | error.LinkFailure => assert(comp.link_diags.hasErrors()), |
| 3116 | 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 | 3118 | gpa, |
| 3119 | 3119 | zcu.navSrcLoc(nav_index), |
| 3120 | 3120 | "unable to codegen: {s}", |
src/link.zig+1-1| ... | ... | @@ -745,7 +745,7 @@ pub const File = struct { |
| 745 | 745 | } |
| 746 | 746 | |
| 747 | 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 | 749 | LinkFailure, |
| 750 | 750 | OutOfMemory, |
| 751 | 751 | }; |
src/link/Coff.zig+3-6| ... | ... | @@ -754,7 +754,7 @@ fn allocateGlobal(coff: *Coff) !u32 { |
| 754 | 754 | return index; |
| 755 | 755 | } |
| 756 | 756 | |
| 757 | fn addGotEntry(coff: *Coff, target: SymbolWithLoc) !void { | |
| 757 | fn addGotEntry(coff: *Coff, target: SymbolWithLoc) error{ OutOfMemory, LinkFailure }!void { | |
| 758 | 758 | const gpa = coff.base.comp.gpa; |
| 759 | 759 | if (coff.got_table.lookup.contains(target)) return; |
| 760 | 760 | const got_index = try coff.got_table.allocateEntry(gpa, target); |
| ... | ... | @@ -780,7 +780,7 @@ pub fn createAtom(coff: *Coff) !Atom.Index { |
| 780 | 780 | return atom_index; |
| 781 | 781 | } |
| 782 | 782 | |
| 783 | fn growAtom(coff: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) !u32 { | |
| 783 | fn growAtom(coff: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignment: u32) link.File.UpdateNavError!u32 { | |
| 784 | 784 | const atom = coff.getAtom(atom_index); |
| 785 | 785 | const sym = atom.getSymbol(coff); |
| 786 | 786 | const align_ok = mem.alignBackward(u32, sym.value, alignment) == sym.value; |
| ... | ... | @@ -1313,10 +1313,7 @@ fn updateLazySymbolAtom( |
| 1313 | 1313 | }; |
| 1314 | 1314 | const code = switch (res) { |
| 1315 | 1315 | .ok => code_buffer.items, |
| 1316 | .fail => |em| { | |
| 1317 | log.err("{s}", .{em.msg}); | |
| 1318 | return error.CodegenFail; | |
| 1319 | }, | |
| 1316 | .fail => |em| return diags.fail("failed to generate code: {s}", .{em.msg}), | |
| 1320 | 1317 | }; |
| 1321 | 1318 | |
| 1322 | 1319 | const code_len: u32 = @intCast(code.len); |
src/link/Dwarf.zig+6-2| ... | ... | @@ -23,6 +23,8 @@ debug_str: StringSection, |
| 23 | 23 | pub const UpdateError = error{ |
| 24 | 24 | /// Indicates the error is already reported on `failed_codegen` in the Zcu. |
| 25 | 25 | CodegenFail, |
| 26 | /// Indicates the error is already reported on `link_diags` in the Compilation. | |
| 27 | LinkFailure, | |
| 26 | 28 | OutOfMemory, |
| 27 | 29 | }; |
| 28 | 30 | |
| ... | ... | @@ -590,12 +592,14 @@ const Unit = struct { |
| 590 | 592 | |
| 591 | 593 | fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void { |
| 592 | 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 | 597 | sec.off(dwarf) + unit.off, |
| 595 | 598 | dwarf.getFile().?, |
| 596 | 599 | sec.off(dwarf) + new_off, |
| 597 | 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 | 603 | unit.off = new_off; |
| 600 | 604 | } |
| 601 | 605 |
src/link/Elf.zig+61-37| ... | ... | @@ -575,7 +575,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) !?u64 { |
| 575 | 575 | } |
| 576 | 576 | } |
| 577 | 577 | |
| 578 | if (at_end) try self.base.file.?.setEndPos(end); | |
| 578 | if (at_end) try self.setEndPos(end); | |
| 579 | 579 | return null; |
| 580 | 580 | } |
| 581 | 581 | |
| ... | ... | @@ -638,7 +638,7 @@ pub fn growSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment: |
| 638 | 638 | |
| 639 | 639 | shdr.sh_offset = new_offset; |
| 640 | 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 | } |
| 644 | 644 | |
| ... | ... | @@ -960,7 +960,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod |
| 960 | 960 | }, |
| 961 | 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 | } |
| 965 | 965 | |
| 966 | 966 | if (has_reloc_errors) return error.LinkFailure; |
| ... | ... | @@ -2117,7 +2117,7 @@ pub fn writeShdrTable(self: *Elf) !void { |
| 2117 | 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 | 2122 | .p64 => { |
| 2123 | 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 | 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 | 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 | 2162 | .p64 => { |
| 2163 | 2163 | const buf = try gpa.alloc(elf.Elf64_Phdr, self.phdrs.items.len); |
| ... | ... | @@ -2169,7 +2169,7 @@ fn writePhdrTable(self: *Elf) !void { |
| 2169 | 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 | 2319 | |
| 2320 | 2320 | assert(index == e_ehsize); |
| 2321 | 2321 | |
| 2322 | try self.base.file.?.pwriteAll(hdr_buf[0..index], 0); | |
| 2322 | try self.pwriteAll(hdr_buf[0..index], 0); | |
| 2323 | 2323 | } |
| 2324 | 2324 | |
| 2325 | 2325 | pub fn freeNav(self: *Elf, nav: InternPool.Nav.Index) void { |
| ... | ... | @@ -2497,8 +2497,8 @@ pub fn writeMergeSections(self: *Elf) !void { |
| 2497 | 2497 | |
| 2498 | 2498 | for (self.merge_sections.items) |*msec| { |
| 2499 | 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; | |
| 2501 | const size = math.cast(usize, msec.size) orelse return error.Overflow; | |
| 2500 | const fileoff = try self.cast(usize, msec.value + shdr.sh_offset); | |
| 2501 | const size = try self.cast(usize, msec.size); | |
| 2502 | 2502 | try buffer.ensureTotalCapacity(size); |
| 2503 | 2503 | buffer.appendNTimesAssumeCapacity(0, size); |
| 2504 | 2504 | |
| ... | ... | @@ -2506,11 +2506,11 @@ pub fn writeMergeSections(self: *Elf) !void { |
| 2506 | 2506 | const msub = msec.mergeSubsection(msub_index); |
| 2507 | 2507 | assert(msub.alive); |
| 2508 | 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 | 2510 | @memcpy(buffer.items[off..][0..string.len], string); |
| 2511 | 2511 | } |
| 2512 | 2512 | |
| 2513 | try self.base.file.?.pwriteAll(buffer.items, fileoff); | |
| 2513 | try self.pwriteAll(buffer.items, fileoff); | |
| 2514 | 2514 | buffer.clearRetainingCapacity(); |
| 2515 | 2515 | } |
| 2516 | 2516 | } |
| ... | ... | @@ -3682,7 +3682,7 @@ fn writeAtoms(self: *Elf) !void { |
| 3682 | 3682 | const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset; |
| 3683 | 3683 | try th.write(self, buffer.writer()); |
| 3684 | 3684 | assert(buffer.items.len == thunk_size); |
| 3685 | try self.base.file.?.pwriteAll(buffer.items, offset); | |
| 3685 | try self.pwriteAll(buffer.items, offset); | |
| 3686 | 3686 | buffer.clearRetainingCapacity(); |
| 3687 | 3687 | } |
| 3688 | 3688 | } |
| ... | ... | @@ -3790,12 +3790,12 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3790 | 3790 | const contents = buffer[0 .. interp.len + 1]; |
| 3791 | 3791 | const shdr = slice.items(.shdr)[shndx]; |
| 3792 | 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 | } |
| 3795 | 3795 | |
| 3796 | 3796 | if (self.section_indexes.hash) |shndx| { |
| 3797 | 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 | } |
| 3800 | 3800 | |
| 3801 | 3801 | if (self.section_indexes.gnu_hash) |shndx| { |
| ... | ... | @@ -3803,12 +3803,12 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3803 | 3803 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.gnu_hash.size()); |
| 3804 | 3804 | defer buffer.deinit(); |
| 3805 | 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 | } |
| 3808 | 3808 | |
| 3809 | 3809 | if (self.section_indexes.versym) |shndx| { |
| 3810 | 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 | } |
| 3813 | 3813 | |
| 3814 | 3814 | if (self.section_indexes.verneed) |shndx| { |
| ... | ... | @@ -3816,7 +3816,7 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3816 | 3816 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.verneed.size()); |
| 3817 | 3817 | defer buffer.deinit(); |
| 3818 | 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 | } |
| 3821 | 3821 | |
| 3822 | 3822 | if (self.section_indexes.dynamic) |shndx| { |
| ... | ... | @@ -3824,7 +3824,7 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3824 | 3824 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynamic.size(self)); |
| 3825 | 3825 | defer buffer.deinit(); |
| 3826 | 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 | } |
| 3829 | 3829 | |
| 3830 | 3830 | if (self.section_indexes.dynsymtab) |shndx| { |
| ... | ... | @@ -3832,12 +3832,12 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3832 | 3832 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynsym.size()); |
| 3833 | 3833 | defer buffer.deinit(); |
| 3834 | 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 | } |
| 3837 | 3837 | |
| 3838 | 3838 | if (self.section_indexes.dynstrtab) |shndx| { |
| 3839 | 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 | } |
| 3842 | 3842 | |
| 3843 | 3843 | if (self.section_indexes.eh_frame) |shndx| { |
| ... | ... | @@ -3847,21 +3847,21 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3847 | 3847 | break :existing_size sym.atom(self).?.size; |
| 3848 | 3848 | }; |
| 3849 | 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 | 3851 | var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size)); |
| 3852 | 3852 | defer buffer.deinit(); |
| 3853 | 3853 | try eh_frame.writeEhFrame(self, buffer.writer()); |
| 3854 | 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 | } |
| 3857 | 3857 | |
| 3858 | 3858 | if (self.section_indexes.eh_frame_hdr) |shndx| { |
| 3859 | 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 | 3861 | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); |
| 3862 | 3862 | defer buffer.deinit(); |
| 3863 | 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 | } |
| 3866 | 3866 | |
| 3867 | 3867 | if (self.section_indexes.got) |index| { |
| ... | ... | @@ -3869,7 +3869,7 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3869 | 3869 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got.size(self)); |
| 3870 | 3870 | defer buffer.deinit(); |
| 3871 | 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 | } |
| 3874 | 3874 | |
| 3875 | 3875 | if (self.section_indexes.rela_dyn) |shndx| { |
| ... | ... | @@ -3877,7 +3877,7 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3877 | 3877 | try self.got.addRela(self); |
| 3878 | 3878 | try self.copy_rel.addRela(self); |
| 3879 | 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 | } |
| 3882 | 3882 | |
| 3883 | 3883 | if (self.section_indexes.plt) |shndx| { |
| ... | ... | @@ -3885,7 +3885,7 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3885 | 3885 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt.size(self)); |
| 3886 | 3886 | defer buffer.deinit(); |
| 3887 | 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 | } |
| 3890 | 3890 | |
| 3891 | 3891 | if (self.section_indexes.got_plt) |shndx| { |
| ... | ... | @@ -3893,7 +3893,7 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3893 | 3893 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got_plt.size(self)); |
| 3894 | 3894 | defer buffer.deinit(); |
| 3895 | 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 | } |
| 3898 | 3898 | |
| 3899 | 3899 | if (self.section_indexes.plt_got) |shndx| { |
| ... | ... | @@ -3901,13 +3901,13 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 3901 | 3901 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt_got.size(self)); |
| 3902 | 3902 | defer buffer.deinit(); |
| 3903 | 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 | } |
| 3906 | 3906 | |
| 3907 | 3907 | if (self.section_indexes.rela_plt) |shndx| { |
| 3908 | 3908 | const shdr = slice.items(.shdr)[shndx]; |
| 3909 | 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 | } |
| 3912 | 3912 | |
| 3913 | 3913 | try self.writeSymtab(); |
| ... | ... | @@ -3919,7 +3919,7 @@ pub fn writeShStrtab(self: *Elf) !void { |
| 3919 | 3919 | if (self.section_indexes.shstrtab) |index| { |
| 3920 | 3920 | const shdr = self.sections.items(.shdr)[index]; |
| 3921 | 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 | } |
| 3925 | 3925 | |
| ... | ... | @@ -3934,7 +3934,7 @@ pub fn writeSymtab(self: *Elf) !void { |
| 3934 | 3934 | .p32 => @sizeOf(elf.Elf32_Sym), |
| 3935 | 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)); | |
| 3938 | 3938 | |
| 3939 | 3939 | log.debug("writing {d} symbols in .symtab from 0x{x} to 0x{x}", .{ |
| 3940 | 3940 | nsyms, |
| ... | ... | @@ -3947,7 +3947,7 @@ pub fn writeSymtab(self: *Elf) !void { |
| 3947 | 3947 | }); |
| 3948 | 3948 | |
| 3949 | 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 | 3951 | // TODO we could resize instead and in ZigObject/Object always access as slice |
| 3952 | 3952 | self.strtab.clearRetainingCapacity(); |
| 3953 | 3953 | self.strtab.appendAssumeCapacity(0); |
| ... | ... | @@ -4016,17 +4016,17 @@ pub fn writeSymtab(self: *Elf) !void { |
| 4016 | 4016 | }; |
| 4017 | 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 | 4021 | .p64 => { |
| 4022 | 4022 | if (foreign_endian) { |
| 4023 | 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 | } |
| 4028 | 4028 | |
| 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 | } |
| 4031 | 4031 | |
| 4032 | 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 | 5190 | return slice[0..mem.indexOfScalar(u8, slice, 0).? :0]; |
| 5191 | 5191 | } |
| 5192 | 5192 | |
| 5193 | pub 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 | ||
| 5201 | pub 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 | ||
| 5209 | pub 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 | ||
| 5193 | 5217 | const std = @import("std"); |
| 5194 | 5218 | const build_options = @import("build_options"); |
| 5195 | 5219 | const 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 | 434 | // libc/libSystem dep |
| 435 | 435 | self.resolveLibSystem(arena, comp, &system_libs) catch |err| switch (err) { |
| 436 | 436 | error.MissingLibSystem => {}, // already reported |
| 437 | else => |e| return e, // TODO: convert into an error | |
| 437 | else => |e| return diags.fail("failed to resolve libSystem: {s}", .{@errorName(e)}), | |
| 438 | 438 | }; |
| 439 | 439 | |
| 440 | 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 | 494 | |
| 495 | 495 | try self.resolveSymbols(); |
| 496 | 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 | }; | |
| 498 | 501 | |
| 499 | 502 | if (self.base.gc_sections) { |
| 500 | 503 | try dead_strip.gcAtoms(self); |
| ... | ... | @@ -551,7 +554,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 551 | 554 | |
| 552 | 555 | try self.writeSectionsToFile(); |
| 553 | 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 | }; | |
| 555 | 562 | |
| 556 | 563 | var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: { |
| 557 | 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 | 568 | // where the code signature goes into. |
| 562 | 569 | var codesig = CodeSignature.init(self.getPageSize()); |
| 563 | 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 | 573 | try self.writeCodeSignaturePadding(&codesig); |
| 566 | 574 | break :blk codesig; |
| 567 | 575 | } else null; |
| ... | ... | @@ -573,13 +581,29 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 573 | 581 | self.getPageSize(), |
| 574 | 582 | ); |
| 575 | 583 | |
| 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 | 589 | try self.writeHeader(ncmds, sizeofcmds); |
| 578 | try self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()); | |
| 579 | if (self.getDebugSymbols()) |dsym| try dsym.flushModule(self); | |
| 590 | self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) { | |
| 591 | error.OutOfMemory => return error.OutOfMemory, | |
| 592 | error.LinkFailure => return error.LinkFailure, | |
| 593 | else => |e| return diags.fail("failed to calculate and write uuid: {s}", .{@errorName(e)}), | |
| 594 | }; | |
| 595 | if (self.getDebugSymbols()) |dsym| dsym.flushModule(self) catch |err| switch (err) { | |
| 596 | error.OutOfMemory => return error.OutOfMemory, | |
| 597 | else => |e| return diags.fail("failed to get debug symbols: {s}", .{@errorName(e)}), | |
| 598 | }; | |
| 580 | 599 | |
| 600 | // Code signing always comes last. | |
| 581 | 601 | if (codesig) |*csig| { |
| 582 | try self.writeCodeSignature(csig); // code signing always comes last | |
| 602 | self.writeCodeSignature(csig) catch |err| switch (err) { | |
| 603 | error.OutOfMemory => return error.OutOfMemory, | |
| 604 | error.LinkFailure => return error.LinkFailure, | |
| 605 | else => |e| return diags.fail("failed to write code signature: {s}", .{@errorName(e)}), | |
| 606 | }; | |
| 583 | 607 | const emit = self.base.emit; |
| 584 | 608 | try invalidateKernelCache(emit.root_dir.handle, emit.sub_path); |
| 585 | 609 | } |
| ... | ... | @@ -2171,7 +2195,7 @@ fn allocateSections(self: *MachO) !void { |
| 2171 | 2195 | fileoff = mem.alignForward(u32, fileoff, page_size); |
| 2172 | 2196 | } |
| 2173 | 2197 | |
| 2174 | const alignment = try math.powi(u32, 2, header.@"align"); | |
| 2198 | const alignment = try self.alignPow(header.@"align"); | |
| 2175 | 2199 | |
| 2176 | 2200 | vmaddr = mem.alignForward(u64, vmaddr, alignment); |
| 2177 | 2201 | header.addr = vmaddr; |
| ... | ... | @@ -2327,7 +2351,7 @@ fn allocateLinkeditSegment(self: *MachO) !void { |
| 2327 | 2351 | seg.vmaddr = mem.alignForward(u64, vmaddr, page_size); |
| 2328 | 2352 | seg.fileoff = mem.alignForward(u64, fileoff, page_size); |
| 2329 | 2353 | |
| 2330 | var off = math.cast(u32, seg.fileoff) orelse return error.Overflow; | |
| 2354 | var off = try self.cast(u32, seg.fileoff); | |
| 2331 | 2355 | // DYLD_INFO_ONLY |
| 2332 | 2356 | { |
| 2333 | 2357 | const cmd = &self.dyld_info_cmd; |
| ... | ... | @@ -2392,7 +2416,7 @@ fn resizeSections(self: *MachO) !void { |
| 2392 | 2416 | if (header.isZerofill()) continue; |
| 2393 | 2417 | if (self.isZigSection(@intCast(n_sect))) continue; // TODO this is horrible |
| 2394 | 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 | 2420 | try out.resize(self.base.comp.gpa, size); |
| 2397 | 2421 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; |
| 2398 | 2422 | @memset(out.items, padding_byte); |
| ... | ... | @@ -2489,7 +2513,7 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void { |
| 2489 | 2513 | |
| 2490 | 2514 | const doWork = struct { |
| 2491 | 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 | 2517 | const size = th.size(); |
| 2494 | 2518 | var stream = std.io.fixedBufferStream(buffer[off..][0..size]); |
| 2495 | 2519 | try th.write(macho_file, stream.writer()); |
| ... | ... | @@ -2601,7 +2625,7 @@ fn writeSectionsToFile(self: *MachO) !void { |
| 2601 | 2625 | |
| 2602 | 2626 | const slice = self.sections.slice(); |
| 2603 | 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 | } |
| 2607 | 2631 | |
| ... | ... | @@ -2644,7 +2668,7 @@ fn writeDyldInfo(self: *MachO) !void { |
| 2644 | 2668 | try self.lazy_bind_section.write(writer); |
| 2645 | 2669 | try stream.seekTo(cmd.export_off - base_off); |
| 2646 | 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 | } |
| 2649 | 2673 | |
| 2650 | 2674 | pub fn writeDataInCode(self: *MachO) !void { |
| ... | ... | @@ -2655,7 +2679,7 @@ pub fn writeDataInCode(self: *MachO) !void { |
| 2655 | 2679 | var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size()); |
| 2656 | 2680 | defer buffer.deinit(); |
| 2657 | 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 | } |
| 2660 | 2684 | |
| 2661 | 2685 | fn writeIndsymtab(self: *MachO) !void { |
| ... | ... | @@ -2667,15 +2691,15 @@ fn writeIndsymtab(self: *MachO) !void { |
| 2667 | 2691 | var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size); |
| 2668 | 2692 | defer buffer.deinit(); |
| 2669 | 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 | } |
| 2672 | 2696 | |
| 2673 | 2697 | pub fn writeSymtabToFile(self: *MachO) !void { |
| 2674 | 2698 | const tracy = trace(@src()); |
| 2675 | 2699 | defer tracy.end(); |
| 2676 | 2700 | const cmd = self.symtab_cmd; |
| 2677 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); | |
| 2678 | try self.base.file.?.pwriteAll(self.strtab.items, cmd.stroff); | |
| 2701 | try self.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); | |
| 2702 | try self.pwriteAll(self.strtab.items, cmd.stroff); | |
| 2679 | 2703 | } |
| 2680 | 2704 | |
| 2681 | 2705 | fn writeUnwindInfo(self: *MachO) !void { |
| ... | ... | @@ -2686,20 +2710,20 @@ fn writeUnwindInfo(self: *MachO) !void { |
| 2686 | 2710 | |
| 2687 | 2711 | if (self.eh_frame_sect_index) |index| { |
| 2688 | 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 | 2714 | const buffer = try gpa.alloc(u8, size); |
| 2691 | 2715 | defer gpa.free(buffer); |
| 2692 | 2716 | eh_frame.write(self, buffer); |
| 2693 | try self.base.file.?.pwriteAll(buffer, header.offset); | |
| 2717 | try self.pwriteAll(buffer, header.offset); | |
| 2694 | 2718 | } |
| 2695 | 2719 | |
| 2696 | 2720 | if (self.unwind_info_sect_index) |index| { |
| 2697 | 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 | 2723 | const buffer = try gpa.alloc(u8, size); |
| 2700 | 2724 | defer gpa.free(buffer); |
| 2701 | 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 | } |
| 2705 | 2729 | |
| ... | ... | @@ -2890,7 +2914,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { |
| 2890 | 2914 | |
| 2891 | 2915 | assert(stream.pos == needed_size); |
| 2892 | 2916 | |
| 2893 | try self.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); | |
| 2917 | try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); | |
| 2894 | 2918 | |
| 2895 | 2919 | return .{ ncmds, buffer.len, uuid_cmd_offset }; |
| 2896 | 2920 | } |
| ... | ... | @@ -2944,7 +2968,7 @@ fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void { |
| 2944 | 2968 | |
| 2945 | 2969 | log.debug("writing Mach-O header {}", .{header}); |
| 2946 | 2970 | |
| 2947 | try self.base.file.?.pwriteAll(mem.asBytes(&header), 0); | |
| 2971 | try self.pwriteAll(mem.asBytes(&header), 0); | |
| 2948 | 2972 | } |
| 2949 | 2973 | |
| 2950 | 2974 | 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 | 2978 | } else self.codesig_cmd.dataoff; |
| 2955 | 2979 | try calcUuid(self.base.comp, self.base.file.?, file_size, &self.uuid_cmd.uuid); |
| 2956 | 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 | } |
| 2959 | 2983 | |
| 2960 | 2984 | pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void { |
| ... | ... | @@ -2968,7 +2992,7 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void { |
| 2968 | 2992 | log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ offset, offset + needed_size }); |
| 2969 | 2993 | // Pad out the space. We need to do this to calculate valid hashes for everything in the file |
| 2970 | 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); | |
| 2972 | 2996 | |
| 2973 | 2997 | self.codesig_cmd.dataoff = @as(u32, @intCast(offset)); |
| 2974 | 2998 | self.codesig_cmd.datasize = @as(u32, @intCast(needed_size)); |
| ... | ... | @@ -2995,7 +3019,7 @@ pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void { |
| 2995 | 3019 | offset + buffer.items.len, |
| 2996 | 3020 | }); |
| 2997 | 3021 | |
| 2998 | try self.base.file.?.pwriteAll(buffer.items, offset); | |
| 3022 | try self.pwriteAll(buffer.items, offset); | |
| 2999 | 3023 | } |
| 3000 | 3024 | |
| 3001 | 3025 | pub fn updateFunc( |
| ... | ... | @@ -3109,7 +3133,7 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) !?u64 { |
| 3109 | 3133 | } |
| 3110 | 3134 | } |
| 3111 | 3135 | |
| 3112 | if (at_end) try self.base.file.?.setEndPos(end); | |
| 3136 | if (at_end) try self.setEndPos(end); | |
| 3113 | 3137 | return null; |
| 3114 | 3138 | } |
| 3115 | 3139 | |
| ... | ... | @@ -3193,22 +3217,25 @@ pub fn findFreeSpaceVirtual(self: *MachO, object_size: u64, min_alignment: u32) |
| 3193 | 3217 | return start; |
| 3194 | 3218 | } |
| 3195 | 3219 | |
| 3196 | pub fn copyRangeAll(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void { | |
| 3220 | pub fn copyRangeAll(self: *MachO, old_offset: u64, new_offset: u64, size: u64) error{LinkFailure}!void { | |
| 3221 | const diags = &self.base.comp.link_diags; | |
| 3197 | 3222 | const file = self.base.file.?; |
| 3198 | const amt = try file.copyRangeAll(old_offset, file, new_offset, size); | |
| 3199 | if (amt != size) return error.InputOutput; | |
| 3223 | const amt = file.copyRangeAll(old_offset, file, new_offset, size) catch |err| | |
| 3224 | return diags.fail("failed to copy file range: {s}", .{@errorName(err)}); | |
| 3225 | if (amt != size) | |
| 3226 | return diags.fail("unexpected short write in copy file range", .{}); | |
| 3200 | 3227 | } |
| 3201 | 3228 | |
| 3202 | 3229 | /// Like File.copyRangeAll but also ensures the source region is zeroed out after copy. |
| 3203 | 3230 | /// This is so that we guarantee zeroed out regions for mapping of zerofill sections by the loader. |
| 3204 | fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void { | |
| 3231 | fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64) error{ LinkFailure, OutOfMemory }!void { | |
| 3205 | 3232 | const gpa = self.base.comp.gpa; |
| 3206 | 3233 | try self.copyRangeAll(old_offset, new_offset, size); |
| 3207 | const size_u = math.cast(usize, size) orelse return error.Overflow; | |
| 3208 | const zeroes = try gpa.alloc(u8, size_u); | |
| 3234 | const size_u = try self.cast(usize, size); | |
| 3235 | const zeroes = try gpa.alloc(u8, size_u); // TODO no need to allocate here. | |
| 3209 | 3236 | defer gpa.free(zeroes); |
| 3210 | 3237 | @memset(zeroes, 0); |
| 3211 | try self.base.file.?.pwriteAll(zeroes, old_offset); | |
| 3238 | try self.pwriteAll(zeroes, old_offset); | |
| 3212 | 3239 | } |
| 3213 | 3240 | |
| 3214 | 3241 | const InitMetadataOptions = struct { |
| ... | ... | @@ -3312,10 +3339,9 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3312 | 3339 | const allocSect = struct { |
| 3313 | 3340 | fn allocSect(macho_file: *MachO, sect_id: u8, size: u64) !void { |
| 3314 | 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 | 3343 | if (!sect.isZerofill()) { |
| 3317 | sect.offset = math.cast(u32, try macho_file.findFreeSpace(size, alignment)) orelse | |
| 3318 | return error.Overflow; | |
| 3344 | sect.offset = try macho_file.cast(u32, try macho_file.findFreeSpace(size, alignment)); | |
| 3319 | 3345 | } |
| 3320 | 3346 | sect.addr = macho_file.findFreeSpaceVirtual(size, alignment); |
| 3321 | 3347 | sect.size = size; |
| ... | ... | @@ -3397,7 +3423,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { |
| 3397 | 3423 | }; |
| 3398 | 3424 | } |
| 3399 | 3425 | |
| 3400 | pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { | |
| 3426 | pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) error{ OutOfMemory, LinkFailure }!void { | |
| 3401 | 3427 | if (self.base.isRelocatable()) { |
| 3402 | 3428 | try self.growSectionRelocatable(sect_index, needed_size); |
| 3403 | 3429 | } else { |
| ... | ... | @@ -3405,7 +3431,7 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void { |
| 3405 | 3431 | } |
| 3406 | 3432 | } |
| 3407 | 3433 | |
| 3408 | fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void { | |
| 3434 | fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) error{ OutOfMemory, LinkFailure }!void { | |
| 3409 | 3435 | const diags = &self.base.comp.link_diags; |
| 3410 | 3436 | const sect = &self.sections.items(.header)[sect_index]; |
| 3411 | 3437 | |
| ... | ... | @@ -3433,7 +3459,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo |
| 3433 | 3459 | |
| 3434 | 3460 | sect.offset = @intCast(new_offset); |
| 3435 | 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 | 3464 | seg.filesize = needed_size; |
| 3439 | 3465 | } |
| ... | ... | @@ -3454,7 +3480,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo |
| 3454 | 3480 | seg.vmsize = needed_size; |
| 3455 | 3481 | } |
| 3456 | 3482 | |
| 3457 | fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void { | |
| 3483 | fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) error{ OutOfMemory, LinkFailure }!void { | |
| 3458 | 3484 | const sect = &self.sections.items(.header)[sect_index]; |
| 3459 | 3485 | |
| 3460 | 3486 | if (!sect.isZerofill()) { |
| ... | ... | @@ -3464,7 +3490,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void |
| 3464 | 3490 | sect.size = 0; |
| 3465 | 3491 | |
| 3466 | 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 | 3494 | const new_offset = try self.findFreeSpace(needed_size, alignment); |
| 3469 | 3495 | const new_addr = self.findFreeSpaceVirtual(needed_size, alignment); |
| 3470 | 3496 | |
| ... | ... | @@ -3482,7 +3508,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void |
| 3482 | 3508 | sect.offset = @intCast(new_offset); |
| 3483 | 3509 | sect.addr = new_addr; |
| 3484 | 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 | 3514 | sect.size = needed_size; |
| ... | ... | @@ -5316,6 +5342,40 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { |
| 5316 | 5342 | return true; |
| 5317 | 5343 | } |
| 5318 | 5344 | |
| 5345 | pub 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 | ||
| 5353 | pub 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 | ||
| 5361 | pub 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 | ||
| 5369 | pub 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 | 5379 | /// Branch instruction has 26 bits immediate but is 4 byte aligned. |
| 5320 | 5380 | const jump_bits = @bitSizeOf(i28); |
| 5321 | 5381 | const 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 | 971 | } |
| 972 | 972 | } |
| 973 | 973 | |
| 974 | pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.relocation_info) !void { | |
| 974 | pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.relocation_info) error{ LinkFailure, OutOfMemory }!void { | |
| 975 | 975 | const tracy = trace(@src()); |
| 976 | 976 | defer tracy.end(); |
| 977 | 977 | |
| ... | ... | @@ -983,15 +983,15 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r |
| 983 | 983 | var i: usize = 0; |
| 984 | 984 | for (relocs) |rel| { |
| 985 | 985 | defer i += 1; |
| 986 | const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow; | |
| 987 | const r_address: i32 = math.cast(i32, self.value + rel_offset) orelse return error.Overflow; | |
| 986 | const rel_offset = try macho_file.cast(usize, rel.offset - self.off); | |
| 987 | const r_address: i32 = try macho_file.cast(i32, self.value + rel_offset); | |
| 988 | 988 | assert(r_address >= 0); |
| 989 | 989 | const r_symbolnum = r_symbolnum: { |
| 990 | 990 | const r_symbolnum: u32 = switch (rel.tag) { |
| 991 | 991 | .local => rel.getTargetAtom(self, macho_file).out_n_sect + 1, |
| 992 | 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 | 996 | const r_extern = rel.tag == .@"extern"; |
| 997 | 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 | 1027 | } else if (addend > 0) { |
| 1028 | 1028 | buffer[i] = .{ |
| 1029 | 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 | 1031 | .r_pcrel = 0, |
| 1032 | 1032 | .r_length = 2, |
| 1033 | 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 | 414 | const rel = relocs[0]; |
| 415 | 415 | assert(rel.tag == .@"extern"); |
| 416 | 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 | 418 | try buffer.ensureUnusedCapacity(target_size); |
| 419 | 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 | 422 | const res = try lp.insert(gpa, header.type(), buffer.items); |
| 422 | 423 | buffer.clearRetainingCapacity(); |
| 423 | 424 | if (!res.found_existing) { |
| ... | ... | @@ -607,10 +608,11 @@ pub fn writeAtoms(self: *InternalObject, macho_file: *MachO) !void { |
| 607 | 608 | if (!atom.isAlive()) continue; |
| 608 | 609 | const sect = atom.getInputSection(macho_file); |
| 609 | 610 | if (sect.isZerofill()) continue; |
| 610 | const off = std.math.cast(usize, atom.value) orelse return error.Overflow; | |
| 611 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | |
| 611 | const off = try macho_file.cast(usize, atom.value); | |
| 612 | const size = try macho_file.cast(usize, atom.size); | |
| 612 | 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 | 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 | 646 | return n_sect; |
| 645 | 647 | } |
| 646 | 648 | |
| 647 | fn getSectionData(self: *const InternalObject, index: u32) error{Overflow}![]const u8 { | |
| 649 | fn getSectionData(self: *const InternalObject, index: u32, macho_file: *MachO) error{LinkFailure}![]const u8 { | |
| 648 | 650 | const slice = self.sections.slice(); |
| 649 | 651 | assert(index < slice.items(.header).len); |
| 650 | 652 | const sect = slice.items(.header)[index]; |
| 651 | 653 | const extra = slice.items(.extra)[index]; |
| 652 | 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 | 656 | return self.objc_methnames.items[sect.offset..][0..size]; |
| 655 | 657 | } else if (extra.is_objc_selref) |
| 656 | 658 | 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 | 582 | ); |
| 583 | 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)); | |
| 586 | 586 | |
| 587 | 587 | for (0..num_ptrs) |i| { |
| 588 | 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 | 650 | |
| 651 | 651 | for (subs.items) |sub| { |
| 652 | 652 | const atom = self.getAtom(sub.atom).?; |
| 653 | const atom_off = math.cast(usize, atom.off) orelse return error.Overflow; | |
| 654 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | |
| 653 | const atom_off = try macho_file.cast(usize, atom.off); | |
| 654 | const atom_size = try macho_file.cast(usize, atom.size); | |
| 655 | 655 | const atom_data = data[atom_off..][0..atom_size]; |
| 656 | 656 | const res = try lp.insert(gpa, header.type(), atom_data); |
| 657 | 657 | if (!res.found_existing) { |
| ... | ... | @@ -674,8 +674,8 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO |
| 674 | 674 | .local => rel.getTargetAtom(atom.*, macho_file), |
| 675 | 675 | .@"extern" => rel.getTargetSymbol(atom.*, macho_file).getAtom(macho_file).?, |
| 676 | 676 | }; |
| 677 | const addend = math.cast(u32, rel.addend) orelse return error.Overflow; | |
| 678 | const target_size = math.cast(usize, target.size) orelse return error.Overflow; | |
| 677 | const addend = try macho_file.cast(u32, rel.addend); | |
| 678 | const target_size = try macho_file.cast(usize, target.size); | |
| 679 | 679 | try buffer.ensureUnusedCapacity(target_size); |
| 680 | 680 | buffer.resize(target_size) catch unreachable; |
| 681 | 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 | 683 | gop.value_ptr.* = try self.readSectionData(gpa, file, @intCast(target.n_sect)); |
| 684 | 684 | } |
| 685 | 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 | 687 | @memcpy(buffer.items, data[target_off..][0..target_size]); |
| 688 | 688 | const res = try lp.insert(gpa, header.type(), buffer.items[addend..]); |
| 689 | 689 | buffer.clearRetainingCapacity(); |
| ... | ... | @@ -1033,7 +1033,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi |
| 1033 | 1033 | const sect = slice.items(.header)[sect_id]; |
| 1034 | 1034 | const relocs = slice.items(.relocs)[sect_id]; |
| 1035 | 1035 | |
| 1036 | const size = math.cast(usize, sect.size) orelse return error.Overflow; | |
| 1036 | const size = try macho_file.cast(usize, sect.size); | |
| 1037 | 1037 | try self.eh_frame_data.resize(allocator, size); |
| 1038 | 1038 | const amt = try file.preadAll(self.eh_frame_data.items, sect.offset + self.offset); |
| 1039 | 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 | 1696 | |
| 1697 | 1697 | pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { |
| 1698 | 1698 | // 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 | 1700 | const basename = std.fs.path.basename(self.path.sub_path); |
| 1701 | 1701 | try Archive.writeHeader(basename, size, ar_format, writer); |
| 1702 | 1702 | // Data |
| ... | ... | @@ -1826,7 +1826,7 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void { |
| 1826 | 1826 | |
| 1827 | 1827 | for (headers, 0..) |header, n_sect| { |
| 1828 | 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 | 1830 | const data = try gpa.alloc(u8, size); |
| 1831 | 1831 | const amt = try file.preadAll(data, header.offset + self.offset); |
| 1832 | 1832 | if (amt != data.len) return error.InputOutput; |
| ... | ... | @@ -1837,9 +1837,9 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void { |
| 1837 | 1837 | if (!atom.isAlive()) continue; |
| 1838 | 1838 | const sect = atom.getInputSection(macho_file); |
| 1839 | 1839 | if (sect.isZerofill()) continue; |
| 1840 | const value = math.cast(usize, atom.value) orelse return error.Overflow; | |
| 1841 | const off = math.cast(usize, atom.off) orelse return error.Overflow; | |
| 1842 | const size = math.cast(usize, atom.size) orelse return error.Overflow; | |
| 1840 | const value = try macho_file.cast(usize, atom.value); | |
| 1841 | const off = try macho_file.cast(usize, atom.off); | |
| 1842 | const size = try macho_file.cast(usize, atom.size); | |
| 1843 | 1843 | const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items; |
| 1844 | 1844 | const data = sections_data[atom.n_sect]; |
| 1845 | 1845 | @memcpy(buffer[value..][0..size], data[off..][0..size]); |
| ... | ... | @@ -1865,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void { |
| 1865 | 1865 | |
| 1866 | 1866 | for (headers, 0..) |header, n_sect| { |
| 1867 | 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 | 1869 | const data = try gpa.alloc(u8, size); |
| 1870 | 1870 | const amt = try file.preadAll(data, header.offset + self.offset); |
| 1871 | 1871 | if (amt != data.len) return error.InputOutput; |
| ... | ... | @@ -1876,9 +1876,9 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void { |
| 1876 | 1876 | if (!atom.isAlive()) continue; |
| 1877 | 1877 | const sect = atom.getInputSection(macho_file); |
| 1878 | 1878 | if (sect.isZerofill()) continue; |
| 1879 | const value = math.cast(usize, atom.value) orelse return error.Overflow; | |
| 1880 | const off = math.cast(usize, atom.off) orelse return error.Overflow; | |
| 1881 | const size = math.cast(usize, atom.size) orelse return error.Overflow; | |
| 1879 | const value = try macho_file.cast(usize, atom.value); | |
| 1880 | const off = try macho_file.cast(usize, atom.off); | |
| 1881 | const size = try macho_file.cast(usize, atom.size); | |
| 1882 | 1882 | const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items; |
| 1883 | 1883 | const data = sections_data[atom.n_sect]; |
| 1884 | 1884 | @memcpy(buffer[value..][0..size], data[off..][0..size]); |
| ... | ... | @@ -1909,29 +1909,27 @@ pub fn calcCompactUnwindSizeRelocatable(self: *Object, macho_file: *MachO) void |
| 1909 | 1909 | } |
| 1910 | 1910 | } |
| 1911 | 1911 | |
| 1912 | fn 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 | ||
| 1912 | 1927 | pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void { |
| 1913 | 1928 | const tracy = trace(@src()); |
| 1914 | 1929 | defer tracy.end(); |
| 1915 | 1930 | |
| 1916 | 1931 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 1917 | 1932 | |
| 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 | 1933 | const nsect = macho_file.unwind_info_sect_index.?; |
| 1936 | 1934 | const buffer = macho_file.sections.items(.out)[nsect].items; |
| 1937 | 1935 | const relocs = macho_file.sections.items(.relocs)[nsect].items; |
| ... | ... | @@ -1967,7 +1965,7 @@ pub fn writeCompactUnwindRelocatable(self: *Object, macho_file: *MachO) !void { |
| 1967 | 1965 | |
| 1968 | 1966 | // Personality function |
| 1969 | 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 | 1969 | var reloc = try addReloc(offset + 16, cpu_arch); |
| 1972 | 1970 | reloc.r_symbolnum = r_symbolnum; |
| 1973 | 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 | 290 | /// We need this so that we can write to an archive. |
| 291 | 291 | /// TODO implement writing ZigObject data directly to a buffer instead. |
| 292 | 292 | pub fn readFileContents(self: *ZigObject, macho_file: *MachO) !void { |
| 293 | const diags = &macho_file.base.comp.link_diags; | |
| 293 | 294 | // Size of the output object file is always the offset + size of the strtab |
| 294 | 295 | const size = macho_file.symtab_cmd.stroff + macho_file.symtab_cmd.strsize; |
| 295 | 296 | const gpa = macho_file.base.comp.gpa; |
| 296 | 297 | try self.data.resize(gpa, size); |
| 297 | const amt = try macho_file.base.file.?.preadAll(self.data.items, 0); | |
| 298 | if (amt != size) return error.InputOutput; | |
| 298 | const amt = macho_file.base.file.?.preadAll(self.data.items, 0) catch |err| | |
| 299 | return diags.fail("failed to read output file: {s}", .{@errorName(err)}); | |
| 300 | if (amt != size) | |
| 301 | return diags.fail("unexpected EOF reading from output file", .{}); | |
| 299 | 302 | } |
| 300 | 303 | |
| 301 | 304 | pub 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 | 379 | if (atom.getRelocs(macho_file).len == 0) continue; |
| 377 | 380 | // TODO: we will resolve and write ZigObject's TLS data twice: |
| 378 | 381 | // 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 | 383 | const code = try gpa.alloc(u8, atom_size); |
| 381 | 384 | defer gpa.free(code); |
| 382 | 385 | self.getAtomData(macho_file, atom.*, code) catch |err| { |
| ... | ... | @@ -400,7 +403,7 @@ pub fn resolveRelocs(self: *ZigObject, macho_file: *MachO) !void { |
| 400 | 403 | has_error = true; |
| 401 | 404 | continue; |
| 402 | 405 | }; |
| 403 | try macho_file.base.file.?.pwriteAll(code, file_offset); | |
| 406 | try macho_file.pwriteAll(code, file_offset); | |
| 404 | 407 | } |
| 405 | 408 | |
| 406 | 409 | if (has_error) return error.ResolveFailed; |
| ... | ... | @@ -419,7 +422,7 @@ pub fn calcNumRelocs(self: *ZigObject, macho_file: *MachO) void { |
| 419 | 422 | } |
| 420 | 423 | } |
| 421 | 424 | |
| 422 | pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void { | |
| 425 | pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) error{ LinkFailure, OutOfMemory }!void { | |
| 423 | 426 | const gpa = macho_file.base.comp.gpa; |
| 424 | 427 | const diags = &macho_file.base.comp.link_diags; |
| 425 | 428 | |
| ... | ... | @@ -432,14 +435,14 @@ pub fn writeRelocs(self: *ZigObject, macho_file: *MachO) !void { |
| 432 | 435 | if (!macho_file.isZigSection(atom.out_n_sect) and !macho_file.isDebugSection(atom.out_n_sect)) continue; |
| 433 | 436 | if (atom.getRelocs(macho_file).len == 0) continue; |
| 434 | 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 | 439 | const code = try gpa.alloc(u8, atom_size); |
| 437 | 440 | defer gpa.free(code); |
| 438 | 441 | self.getAtomData(macho_file, atom.*, code) catch |err| |
| 439 | 442 | return diags.fail("failed to fetch code for '{s}': {s}", .{ atom.getName(macho_file), @errorName(err) }); |
| 440 | 443 | const file_offset = header.offset + atom.value; |
| 441 | 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 | } |
| 445 | 448 | |
| ... | ... | @@ -457,8 +460,8 @@ pub fn writeAtomsRelocatable(self: *ZigObject, macho_file: *MachO) !void { |
| 457 | 460 | if (sect.isZerofill()) continue; |
| 458 | 461 | if (macho_file.isZigSection(atom.out_n_sect)) continue; |
| 459 | 462 | if (atom.getRelocs(macho_file).len == 0) continue; |
| 460 | const off = std.math.cast(usize, atom.value) orelse return error.Overflow; | |
| 461 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | |
| 463 | const off = try macho_file.cast(usize, atom.value); | |
| 464 | const size = try macho_file.cast(usize, atom.size); | |
| 462 | 465 | const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items; |
| 463 | 466 | try self.getAtomData(macho_file, atom.*, buffer[off..][0..size]); |
| 464 | 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 | 483 | const sect = atom.getInputSection(macho_file); |
| 481 | 484 | if (sect.isZerofill()) continue; |
| 482 | 485 | if (macho_file.isZigSection(atom.out_n_sect)) continue; |
| 483 | const off = std.math.cast(usize, atom.value) orelse return error.Overflow; | |
| 484 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | |
| 486 | const off = try macho_file.cast(usize, atom.value); | |
| 487 | const size = try macho_file.cast(usize, atom.size); | |
| 485 | 488 | const buffer = macho_file.sections.items(.out)[atom.out_n_sect].items; |
| 486 | 489 | try self.getAtomData(macho_file, atom.*, buffer[off..][0..size]); |
| 487 | 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 | 549 | return sect; |
| 547 | 550 | } |
| 548 | 551 | |
| 549 | pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) !void { | |
| 552 | pub 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 | 555 | // Handle any lazy symbols that were emitted by incremental compilation. |
| 551 | 556 | if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| { |
| 552 | 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 | 559 | |
| 555 | 560 | // Most lazy symbols can be updated on first use, but |
| 556 | 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 | 563 | macho_file, |
| 559 | 564 | pt, |
| 560 | 565 | .{ .kind = .code, .ty = .anyerror_type }, |
| 561 | 566 | metadata.text_symbol_index, |
| 562 | ) catch |err| return switch (err) { | |
| 563 | error.CodegenFail => error.LinkFailure, | |
| 564 | else => |e| e, | |
| 565 | }; | |
| 566 | if (metadata.const_state != .unused) self.updateLazySymbol( | |
| 567 | ); | |
| 568 | if (metadata.const_state != .unused) try self.updateLazySymbol( | |
| 567 | 569 | macho_file, |
| 568 | 570 | pt, |
| 569 | 571 | .{ .kind = .const_data, .ty = .anyerror_type }, |
| 570 | 572 | metadata.const_symbol_index, |
| 571 | ) catch |err| return switch (err) { | |
| 572 | error.CodegenFail => error.LinkFailure, | |
| 573 | else => |e| e, | |
| 574 | }; | |
| 573 | ); | |
| 575 | 574 | } |
| 576 | 575 | for (self.lazy_syms.values()) |*metadata| { |
| 577 | 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 | 580 | if (self.dwarf) |*dwarf| { |
| 582 | 581 | const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid); |
| 583 | 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 | }; | |
| 585 | 588 | |
| 586 | 589 | self.debug_abbrev_dirty = false; |
| 587 | 590 | self.debug_aranges_dirty = false; |
| ... | ... | @@ -616,6 +619,7 @@ pub fn getNavVAddr( |
| 616 | 619 | const sym = self.symbols.items[sym_index]; |
| 617 | 620 | const vaddr = sym.getAddress(.{}, macho_file); |
| 618 | 621 | switch (reloc_info.parent) { |
| 622 | .none => unreachable, | |
| 619 | 623 | .atom_index => |atom_index| { |
| 620 | 624 | const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?; |
| 621 | 625 | try parent_atom.addReloc(macho_file, .{ |
| ... | ... | @@ -655,6 +659,7 @@ pub fn getUavVAddr( |
| 655 | 659 | const sym = self.symbols.items[sym_index]; |
| 656 | 660 | const vaddr = sym.getAddress(.{}, macho_file); |
| 657 | 661 | switch (reloc_info.parent) { |
| 662 | .none => unreachable, | |
| 658 | 663 | .atom_index => |atom_index| { |
| 659 | 664 | const parent_atom = self.symbols.items[atom_index].getAtom(macho_file).?; |
| 660 | 665 | try parent_atom.addReloc(macho_file, .{ |
| ... | ... | @@ -766,7 +771,7 @@ pub fn updateFunc( |
| 766 | 771 | func_index: InternPool.Index, |
| 767 | 772 | air: Air, |
| 768 | 773 | liveness: Liveness, |
| 769 | ) !void { | |
| 774 | ) link.File.UpdateNavError!void { | |
| 770 | 775 | const tracy = trace(@src()); |
| 771 | 776 | defer tracy.end(); |
| 772 | 777 | |
| ... | ... | @@ -936,7 +941,7 @@ fn updateNavCode( |
| 936 | 941 | sym_index: Symbol.Index, |
| 937 | 942 | sect_index: u8, |
| 938 | 943 | code: []const u8, |
| 939 | ) !void { | |
| 944 | ) link.File.UpdateNavError!void { | |
| 940 | 945 | const zcu = pt.zcu; |
| 941 | 946 | const gpa = zcu.gpa; |
| 942 | 947 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -950,6 +955,7 @@ fn updateNavCode( |
| 950 | 955 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), |
| 951 | 956 | }; |
| 952 | 957 | |
| 958 | const diags = &macho_file.base.comp.link_diags; | |
| 953 | 959 | const sect = &macho_file.sections.items(.header)[sect_index]; |
| 954 | 960 | const sym = &self.symbols.items[sym_index]; |
| 955 | 961 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| ... | ... | @@ -978,7 +984,7 @@ fn updateNavCode( |
| 978 | 984 | const need_realloc = code.len > capacity or !required_alignment.check(atom.value); |
| 979 | 985 | |
| 980 | 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 | 988 | log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value }); |
| 983 | 989 | if (old_vaddr != atom.value) { |
| 984 | 990 | sym.value = 0; |
| ... | ... | @@ -1000,7 +1006,7 @@ fn updateNavCode( |
| 1000 | 1006 | |
| 1001 | 1007 | if (!sect.isZerofill()) { |
| 1002 | 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 | } |
| 1006 | 1012 | |
| ... | ... | @@ -1236,7 +1242,7 @@ fn lowerConst( |
| 1236 | 1242 | |
| 1237 | 1243 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| 1238 | 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); | |
| 1240 | 1246 | |
| 1241 | 1247 | return .{ .ok = sym_index }; |
| 1242 | 1248 | } |
| ... | ... | @@ -1347,9 +1353,10 @@ fn updateLazySymbol( |
| 1347 | 1353 | pt: Zcu.PerThread, |
| 1348 | 1354 | lazy_sym: link.File.LazySymbol, |
| 1349 | 1355 | symbol_index: Symbol.Index, |
| 1350 | ) !void { | |
| 1356 | ) error{ OutOfMemory, LinkFailure }!void { | |
| 1351 | 1357 | const zcu = pt.zcu; |
| 1352 | 1358 | const gpa = zcu.gpa; |
| 1359 | const diags = &macho_file.base.comp.link_diags; | |
| 1353 | 1360 | |
| 1354 | 1361 | var required_alignment: Atom.Alignment = .none; |
| 1355 | 1362 | var code_buffer = std.ArrayList(u8).init(gpa); |
| ... | ... | @@ -1365,7 +1372,7 @@ fn updateLazySymbol( |
| 1365 | 1372 | }; |
| 1366 | 1373 | |
| 1367 | 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 | 1376 | &macho_file.base, |
| 1370 | 1377 | pt, |
| 1371 | 1378 | src, |
| ... | ... | @@ -1374,13 +1381,14 @@ fn updateLazySymbol( |
| 1374 | 1381 | &code_buffer, |
| 1375 | 1382 | .none, |
| 1376 | 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 | 1389 | const code = switch (res) { |
| 1379 | 1390 | .ok => code_buffer.items, |
| 1380 | .fail => |em| { | |
| 1381 | log.err("{s}", .{em.msg}); | |
| 1382 | return error.CodegenFail; | |
| 1383 | }, | |
| 1391 | .fail => |em| return diags.fail("codegen failure: {s}", .{em.msg}), | |
| 1384 | 1392 | }; |
| 1385 | 1393 | |
| 1386 | 1394 | const output_section_index = switch (lazy_sym.kind) { |
| ... | ... | @@ -1412,7 +1420,7 @@ fn updateLazySymbol( |
| 1412 | 1420 | |
| 1413 | 1421 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| 1414 | 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 | } |
| 1417 | 1425 | |
| 1418 | 1426 | pub 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 | 1494 | .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf), |
| 1487 | 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 | } |
| 1491 | 1499 | |
| 1492 | 1500 | pub 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 | 18 | // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all |
| 19 | 19 | // debug info segments/sections (this is apparently by design by Apple), we copy |
| 20 | 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 | 21 | const path = positionals.items[0].path().?; |
| 24 | const in_file = try path.root_dir.handle.openFile(path.sub_path, .{}); | |
| 25 | const stat = try in_file.stat(); | |
| 26 | const amt = try in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size); | |
| 27 | if (amt != stat.size) return error.InputOutput; // TODO: report an actual user error | |
| 22 | const in_file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err| | |
| 23 | return diags.fail("failed to open {}: {s}", .{ path, @errorName(err) }); | |
| 24 | const stat = in_file.stat() catch |err| | |
| 25 | return diags.fail("failed to stat {}: {s}", .{ path, @errorName(err) }); | |
| 26 | const amt = in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size) catch |err| | |
| 27 | return diags.fail("failed to copy range of file {}: {s}", .{ path, @errorName(err) }); | |
| 28 | if (amt != stat.size) | |
| 29 | return diags.fail("unexpected short write in copy range of file {}", .{path}); | |
| 28 | 30 | return; |
| 29 | 31 | } |
| 30 | 32 | |
| ... | ... | @@ -40,7 +42,11 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat |
| 40 | 42 | if (diags.hasErrors()) return error.LinkFailure; |
| 41 | 43 | |
| 42 | 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 | 50 | markExports(macho_file); |
| 45 | 51 | claimUnresolved(macho_file); |
| 46 | 52 | try initOutputSections(macho_file); |
| ... | ... | @@ -108,7 +114,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 108 | 114 | try macho_file.addAtomsToSections(); |
| 109 | 115 | try calcSectionSizes(macho_file); |
| 110 | 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 | 119 | allocateSegment(macho_file); |
| 113 | 120 | |
| 114 | 121 | if (build_options.enable_logging) { |
| ... | ... | @@ -126,8 +133,6 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 126 | 133 | const ncmds, const sizeofcmds = try writeLoadCommands(macho_file); |
| 127 | 134 | try writeHeader(macho_file, ncmds, sizeofcmds); |
| 128 | 135 | |
| 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 | 136 | try zo.readFileContents(macho_file); |
| 132 | 137 | } |
| 133 | 138 | |
| ... | ... | @@ -152,7 +157,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 152 | 157 | |
| 153 | 158 | // Update sizes of contributing objects |
| 154 | 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 | } |
| 157 | 163 | |
| 158 | 164 | // Update file offsets of contributing objects |
| ... | ... | @@ -171,7 +177,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 171 | 177 | state.file_off = pos; |
| 172 | 178 | pos += @sizeOf(Archive.ar_hdr); |
| 173 | 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 | 182 | .object => |o| { |
| 177 | 183 | const state = &o.output_ar_state; |
| ... | ... | @@ -179,7 +185,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 179 | 185 | state.file_off = pos; |
| 180 | 186 | pos += @sizeOf(Archive.ar_hdr); |
| 181 | 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 | 190 | else => unreachable, |
| 185 | 191 | } |
| ... | ... | @@ -201,7 +207,10 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 201 | 207 | try writer.writeAll(Archive.ARMAG); |
| 202 | 208 | |
| 203 | 209 | // 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 | }; | |
| 205 | 214 | |
| 206 | 215 | // Write object files |
| 207 | 216 | for (files.items) |index| { |
| ... | ... | @@ -210,13 +219,14 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 210 | 219 | if (padding > 0) { |
| 211 | 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 | } |
| 215 | 225 | |
| 216 | 226 | assert(buffer.items.len == total_size); |
| 217 | 227 | |
| 218 | try macho_file.base.file.?.setEndPos(total_size); | |
| 219 | try macho_file.base.file.?.pwriteAll(buffer.items, 0); | |
| 228 | try macho_file.setEndPos(total_size); | |
| 229 | try macho_file.pwriteAll(buffer.items, 0); | |
| 220 | 230 | |
| 221 | 231 | if (diags.hasErrors()) return error.LinkFailure; |
| 222 | 232 | } |
| ... | ... | @@ -452,11 +462,10 @@ fn allocateSections(macho_file: *MachO) !void { |
| 452 | 462 | for (slice.items(.header)) |*header| { |
| 453 | 463 | const needed_size = header.size; |
| 454 | 464 | header.size = 0; |
| 455 | const alignment = try math.powi(u32, 2, header.@"align"); | |
| 465 | const alignment = try macho_file.alignPow(header.@"align"); | |
| 456 | 466 | if (!header.isZerofill()) { |
| 457 | 467 | if (needed_size > macho_file.allocatedSize(header.offset)) { |
| 458 | header.offset = math.cast(u32, try macho_file.findFreeSpace(needed_size, alignment)) orelse | |
| 459 | return error.Overflow; | |
| 468 | header.offset = try macho_file.cast(u32, try macho_file.findFreeSpace(needed_size, alignment)); | |
| 460 | 469 | } |
| 461 | 470 | } |
| 462 | 471 | if (needed_size > macho_file.allocatedSizeVirtual(header.addr)) { |
| ... | ... | @@ -572,7 +581,7 @@ fn sortRelocs(macho_file: *MachO) void { |
| 572 | 581 | } |
| 573 | 582 | } |
| 574 | 583 | |
| 575 | fn writeSections(macho_file: *MachO) !void { | |
| 584 | fn writeSections(macho_file: *MachO) link.File.FlushError!void { | |
| 576 | 585 | const tracy = trace(@src()); |
| 577 | 586 | defer tracy.end(); |
| 578 | 587 | |
| ... | ... | @@ -583,7 +592,7 @@ fn writeSections(macho_file: *MachO) !void { |
| 583 | 592 | for (slice.items(.header), slice.items(.out), slice.items(.relocs), 0..) |header, *out, *relocs, n_sect| { |
| 584 | 593 | if (header.isZerofill()) continue; |
| 585 | 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 | 596 | try out.resize(gpa, size); |
| 588 | 597 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; |
| 589 | 598 | @memset(out.items, padding_byte); |
| ... | ... | @@ -662,16 +671,16 @@ fn writeSectionsToFile(macho_file: *MachO) !void { |
| 662 | 671 | |
| 663 | 672 | const slice = macho_file.sections.slice(); |
| 664 | 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); | |
| 666 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | |
| 674 | try macho_file.pwriteAll(out.items, header.offset); | |
| 675 | try macho_file.pwriteAll(mem.sliceAsBytes(relocs.items), header.reloff); | |
| 667 | 676 | } |
| 668 | 677 | |
| 669 | 678 | try macho_file.writeDataInCode(); |
| 670 | try macho_file.base.file.?.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff); | |
| 671 | try macho_file.base.file.?.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff); | |
| 679 | try macho_file.pwriteAll(mem.sliceAsBytes(macho_file.symtab.items), macho_file.symtab_cmd.symoff); | |
| 680 | try macho_file.pwriteAll(macho_file.strtab.items, macho_file.symtab_cmd.stroff); | |
| 672 | 681 | } |
| 673 | 682 | |
| 674 | fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { | |
| 683 | fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } { | |
| 675 | 684 | const gpa = macho_file.base.comp.gpa; |
| 676 | 685 | const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file); |
| 677 | 686 | const buffer = try gpa.alloc(u8, needed_size); |
| ... | ... | @@ -686,31 +695,45 @@ fn writeLoadCommands(macho_file: *MachO) !struct { usize, usize } { |
| 686 | 695 | { |
| 687 | 696 | assert(macho_file.segments.items.len == 1); |
| 688 | 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 | 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 | 706 | ncmds += 1; |
| 694 | 707 | } |
| 695 | 708 | |
| 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 | 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 | 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 | 720 | ncmds += 1; |
| 702 | 721 | |
| 703 | 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 | 726 | ncmds += 1; |
| 706 | 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 | 731 | ncmds += 1; |
| 709 | 732 | } |
| 710 | 733 | |
| 711 | 734 | assert(stream.pos == needed_size); |
| 712 | 735 | |
| 713 | try macho_file.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); | |
| 736 | try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); | |
| 714 | 737 | |
| 715 | 738 | return .{ ncmds, buffer.len }; |
| 716 | 739 | } |
| ... | ... | @@ -742,7 +765,7 @@ fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { |
| 742 | 765 | header.ncmds = @intCast(ncmds); |
| 743 | 766 | header.sizeofcmds = @intCast(sizeofcmds); |
| 744 | 767 | |
| 745 | try macho_file.base.file.?.pwriteAll(mem.asBytes(&header), 0); | |
| 768 | try macho_file.pwriteAll(mem.asBytes(&header), 0); | |
| 746 | 769 | } |
| 747 | 770 | |
| 748 | 771 | const std = @import("std"); |
src/link/Plan9.zig+38-25| ... | ... | @@ -535,16 +535,21 @@ fn allocateGotIndex(self: *Plan9) usize { |
| 535 | 535 | } |
| 536 | 536 | } |
| 537 | 537 | |
| 538 | pub fn flush(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { | |
| 538 | pub 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 | 544 | const comp = self.base.comp; |
| 545 | const diags = &comp.link_diags; | |
| 540 | 546 | const use_lld = build_options.have_llvm and comp.config.use_lld; |
| 541 | 547 | assert(!use_lld); |
| 542 | 548 | |
| 543 | 549 | switch (link.File.effectiveOutputMode(use_lld, comp.config.output_mode)) { |
| 544 | 550 | .Exe => {}, |
| 545 | // plan9 object files are totally different | |
| 546 | .Obj => return error.TODOImplementPlan9Objs, | |
| 547 | .Lib => return error.TODOImplementWritingLibFiles, | |
| 551 | .Obj => return diags.fail("writing plan9 object files unimplemented", .{}), | |
| 552 | .Lib => return diags.fail("writing plan9 lib files unimplemented", .{}), | |
| 548 | 553 | } |
| 549 | 554 | return self.flushModule(arena, tid, prog_node); |
| 550 | 555 | } |
| ... | ... | @@ -589,7 +594,13 @@ fn atomCount(self: *Plan9) usize { |
| 589 | 594 | return data_nav_count + fn_nav_count + lazy_atom_count + extern_atom_count + uav_atom_count; |
| 590 | 595 | } |
| 591 | 596 | |
| 592 | pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { | |
| 597 | pub 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 | 604 | if (build_options.skip_non_native and builtin.object_format != .plan9) { |
| 594 | 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 | 611 | _ = arena; // Has the same lifetime as the call to Compilation.update. |
| 601 | 612 | |
| 602 | 613 | const comp = self.base.comp; |
| 614 | const diags = &comp.link_diags; | |
| 603 | 615 | const gpa = comp.gpa; |
| 604 | 616 | const target = comp.root_mod.resolved_target.result; |
| 605 | 617 | |
| ... | ... | @@ -611,7 +623,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 611 | 623 | defer assert(self.hdr.entry != 0x0); |
| 612 | 624 | |
| 613 | 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 | 627 | tid, |
| 616 | 628 | ); |
| 617 | 629 | defer pt.deactivate(); |
| ... | ... | @@ -620,22 +632,16 @@ pub fn flushModule(self: *Plan9, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 620 | 632 | if (self.lazy_syms.getPtr(.none)) |metadata| { |
| 621 | 633 | // Most lazy symbols can be updated on first use, but |
| 622 | 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 | 636 | pt, |
| 625 | 637 | .{ .kind = .code, .ty = .anyerror_type }, |
| 626 | 638 | metadata.text_atom, |
| 627 | ) catch |err| return switch (err) { | |
| 628 | error.CodegenFail => error.LinkFailure, | |
| 629 | else => |e| e, | |
| 630 | }; | |
| 631 | if (metadata.rodata_state != .unused) self.updateLazySymbolAtom( | |
| 639 | ); | |
| 640 | if (metadata.rodata_state != .unused) try self.updateLazySymbolAtom( | |
| 632 | 641 | pt, |
| 633 | 642 | .{ .kind = .const_data, .ty = .anyerror_type }, |
| 634 | 643 | metadata.rodata_atom, |
| 635 | ) catch |err| return switch (err) { | |
| 636 | error.CodegenFail => error.LinkFailure, | |
| 637 | else => |e| e, | |
| 638 | }; | |
| 644 | ); | |
| 639 | 645 | } |
| 640 | 646 | for (self.lazy_syms.values()) |*metadata| { |
| 641 | 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 | 914 | } |
| 909 | 915 | } |
| 910 | 916 | } |
| 911 | // write it all! | |
| 912 | try file.pwritevAll(iovecs, 0); | |
| 917 | file.pwritevAll(iovecs, 0) catch |err| return diags.fail("failed to write file: {s}", .{@errorName(err)}); | |
| 913 | 918 | } |
| 914 | 919 | fn addNavExports( |
| 915 | 920 | self: *Plan9, |
| ... | ... | @@ -1047,8 +1052,15 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, pt: Zcu.PerThread, lazy_sym: F |
| 1047 | 1052 | return atom; |
| 1048 | 1053 | } |
| 1049 | 1054 | |
| 1050 | fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, atom_index: Atom.Index) !void { | |
| 1055 | fn updateLazySymbolAtom( | |
| 1056 | self: *Plan9, | |
| 1057 | pt: Zcu.PerThread, | |
| 1058 | sym: File.LazySymbol, | |
| 1059 | atom_index: Atom.Index, | |
| 1060 | ) error{ LinkFailure, OutOfMemory }!void { | |
| 1051 | 1061 | const gpa = pt.zcu.gpa; |
| 1062 | const comp = self.base.comp; | |
| 1063 | const diags = &comp.link_diags; | |
| 1052 | 1064 | |
| 1053 | 1065 | var required_alignment: InternPool.Alignment = .none; |
| 1054 | 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 | 1081 | |
| 1070 | 1082 | // generate the code |
| 1071 | 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 | 1085 | &self.base, |
| 1074 | 1086 | pt, |
| 1075 | 1087 | src, |
| ... | ... | @@ -1078,13 +1090,14 @@ fn updateLazySymbolAtom(self: *Plan9, pt: Zcu.PerThread, sym: File.LazySymbol, a |
| 1078 | 1090 | &code_buffer, |
| 1079 | 1091 | .none, |
| 1080 | 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 | 1098 | const code = switch (res) { |
| 1083 | 1099 | .ok => code_buffer.items, |
| 1084 | .fail => |em| { | |
| 1085 | log.err("{s}", .{em.msg}); | |
| 1086 | return error.CodegenFail; | |
| 1087 | }, | |
| 1100 | .fail => |em| return diags.fail("codegen failure: {s}", .{em.msg}), | |
| 1088 | 1101 | }; |
| 1089 | 1102 | // duped_code is freed when the atom is freed |
| 1090 | 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 | 206 | return self.flushModule(arena, tid, prog_node); |
| 207 | 207 | } |
| 208 | 208 | |
| 209 | pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { | |
| 209 | pub 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 | 220 | if (build_options.skip_non_native) { |
| 211 | 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 | 227 | const sub_prog_node = prog_node.start("Flush Module", 0); |
| 218 | 228 | defer sub_prog_node.end(); |
| 219 | 229 | |
| 220 | const spv = &self.object.spv; | |
| 221 | ||
| 222 | 230 | const comp = self.base.comp; |
| 231 | const spv = &self.object.spv; | |
| 232 | const diags = &comp.link_diags; | |
| 223 | 233 | const gpa = comp.gpa; |
| 224 | 234 | const target = comp.getTarget(); |
| 225 | _ = tid; | |
| 226 | 235 | |
| 227 | 236 | try writeCapabilities(spv, target); |
| 228 | 237 | try writeMemoryModel(spv, target); |
| ... | ... | @@ -265,13 +274,11 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 265 | 274 | |
| 266 | 275 | const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) { |
| 267 | 276 | error.OutOfMemory => return error.OutOfMemory, |
| 268 | else => |other| { | |
| 269 | log.err("error while linking: {s}", .{@errorName(other)}); | |
| 270 | return error.LinkFailure; | |
| 271 | }, | |
| 277 | else => |other| return diags.fail("error while linking: {s}", .{@errorName(other)}), | |
| 272 | 278 | }; |
| 273 | 279 | |
| 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 | } |
| 276 | 283 | |
| 277 | 284 | fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: std.Progress.Node) ![]Word { |
src/link/Wasm.zig+137-25| ... | ... | @@ -1,3 +1,14 @@ |
| 1 | //! The overall strategy here is to load all the object file data into memory | |
| 2 | //! as inputs are parsed. During `prelink`, as much linking as possible is | |
| 3 | //! performed without any knowledge of functions and globals provided by the | |
| 4 | //! Zcu. If there is no Zcu, effectively all linking is done in `prelink`. | |
| 5 | //! | |
| 6 | //! `updateFunc`, `updateNav`, `updateExports`, and `deleteExport` are handled | |
| 7 | //! by merely tracking references to the relevant functions and globals. All | |
| 8 | //! the linking logic between objects and Zcu happens in `flush`. Many | |
| 9 | //! components of the final output are computed on-the-fly at this time rather | |
| 10 | //! than being precomputed and stored separately. | |
| 11 | ||
| 1 | 12 | const Wasm = @This(); |
| 2 | 13 | const Archive = @import("Wasm/Archive.zig"); |
| 3 | 14 | const Object = @import("Wasm/Object.zig"); |
| ... | ... | @@ -164,10 +175,12 @@ functions: std.AutoArrayHashMapUnmanaged(FunctionImport.Resolution, void) = .emp |
| 164 | 175 | functions_len: u32 = 0, |
| 165 | 176 | /// Immutable after prelink. The undefined functions coming only from all object files. |
| 166 | 177 | /// The Zcu must satisfy these. |
| 167 | function_imports_init: []FunctionImportId = &.{}, | |
| 168 | /// Initialized as copy of `function_imports_init`; entries are deleted as | |
| 169 | /// they are satisfied by the Zcu. | |
| 170 | function_imports: std.AutoArrayHashMapUnmanaged(FunctionImportId, void) = .empty, | |
| 178 | function_imports_init_keys: []String = &.{}, | |
| 179 | function_imports_init_vals: []FunctionImportId = &.{}, | |
| 180 | /// Initialized as copy of `function_imports_init_keys` and | |
| 181 | /// `function_import_init_vals`; entries are deleted as they are satisfied by | |
| 182 | /// the Zcu. | |
| 183 | function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImportId) = .empty, | |
| 171 | 184 | |
| 172 | 185 | /// Ordered list of non-import globals that will appear in the final binary. |
| 173 | 186 | /// Empty until prelink. |
| ... | ... | @@ -175,38 +188,53 @@ globals: std.AutoArrayHashMapUnmanaged(GlobalImport.Resolution, void) = .empty, |
| 175 | 188 | /// Tracks the value at the end of prelink, at which point `globals` |
| 176 | 189 | /// contains only object file globals, and nothing from the Zcu yet. |
| 177 | 190 | globals_len: u32 = 0, |
| 178 | global_imports_init: []GlobalImportId = &.{}, | |
| 179 | global_imports: std.AutoArrayHashMapUnmanaged(GlobalImportId, void) = .empty, | |
| 191 | global_imports_init_keys: []String = &.{}, | |
| 192 | global_imports_init_vals: []GlobalImportId = &.{}, | |
| 193 | global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImportId) = .empty, | |
| 180 | 194 | |
| 181 | 195 | /// Ordered list of non-import tables that will appear in the final binary. |
| 182 | 196 | /// Empty until prelink. |
| 183 | 197 | tables: std.AutoArrayHashMapUnmanaged(TableImport.Resolution, void) = .empty, |
| 184 | table_imports: std.AutoArrayHashMapUnmanaged(ObjectTableImportIndex, void) = .empty, | |
| 198 | table_imports: std.AutoArrayHashMapUnmanaged(String, ObjectTableImportIndex) = .empty, | |
| 185 | 199 | |
| 186 | 200 | any_exports_updated: bool = true, |
| 187 | 201 | |
| 202 | /// Index into `objects`. | |
| 203 | pub const ObjectIndex = enum(u32) { | |
| 204 | _, | |
| 205 | }; | |
| 206 | ||
| 188 | 207 | /// Index into `functions`. |
| 189 | 208 | pub const FunctionIndex = enum(u32) { |
| 190 | 209 | _, |
| 191 | 210 | |
| 192 | pub fn fromNav(nav_index: InternPool.Nav.Index, wasm: *const Wasm) FunctionIndex { | |
| 193 | return @enumFromInt(wasm.functions.getIndex(.pack(wasm, .{ .nav = nav_index })).?); | |
| 211 | pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?FunctionIndex { | |
| 212 | const i = wasm.functions.getIndex(.fromIpNav(wasm, nav_index)) orelse return null; | |
| 213 | return @enumFromInt(i); | |
| 194 | 214 | } |
| 195 | 215 | }; |
| 196 | 216 | |
| 197 | 217 | /// 0. Index into `function_imports` |
| 198 | 218 | /// 1. Index into `functions`. |
| 219 | /// | |
| 220 | /// Note that function_imports indexes are subject to swap removals during | |
| 221 | /// `flush`. | |
| 199 | 222 | pub const OutputFunctionIndex = enum(u32) { |
| 200 | 223 | _, |
| 201 | 224 | }; |
| 202 | 225 | |
| 203 | 226 | /// Index into `globals`. |
| 204 | const GlobalIndex = enum(u32) { | |
| 227 | pub const GlobalIndex = enum(u32) { | |
| 205 | 228 | _, |
| 206 | 229 | |
| 207 | 230 | fn key(index: GlobalIndex, f: *const Flush) *Wasm.GlobalImport.Resolution { |
| 208 | 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 | }; |
| 211 | 239 | |
| 212 | 240 | /// The first N indexes correspond to input objects (`objects`) array. |
| ... | ... | @@ -218,6 +246,38 @@ pub const SourceLocation = enum(u32) { |
| 218 | 246 | zig_object_nofile = std.math.maxInt(u32) - 1, |
| 219 | 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 | }; |
| 222 | 282 | |
| 223 | 283 | /// The lower bits of this ABI-match the flags here: |
| ... | ... | @@ -445,6 +505,10 @@ pub const FunctionImport = extern struct { |
| 445 | 505 | }; |
| 446 | 506 | } |
| 447 | 507 | |
| 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 | 512 | pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool { |
| 449 | 513 | return switch (r.unpack(wasm)) { |
| 450 | 514 | .unresolved, .nav => true, |
| ... | ... | @@ -587,6 +651,10 @@ pub const ObjectGlobalImportIndex = enum(u32) { |
| 587 | 651 | /// Index into `object_table_imports`. |
| 588 | 652 | pub 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 | }; |
| 591 | 659 | |
| 592 | 660 | /// Index into `object_tables`. |
| ... | ... | @@ -797,12 +865,48 @@ pub const ValtypeList = enum(u32) { |
| 797 | 865 | /// 1. Index into `imports`. |
| 798 | 866 | pub 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 | }; |
| 801 | 887 | |
| 802 | 888 | /// 0. Index into `object_global_imports`. |
| 803 | 889 | /// 1. Index into `imports`. |
| 804 | 890 | pub 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 | }; |
| 807 | 911 | |
| 808 | 912 | pub const Relocation = struct { |
| ... | ... | @@ -897,7 +1001,7 @@ pub const InitFunc = extern struct { |
| 897 | 1001 | priority: u32, |
| 898 | 1002 | function_index: ObjectFunctionIndex, |
| 899 | 1003 | |
| 900 | fn lessThan(ctx: void, lhs: InitFunc, rhs: InitFunc) bool { | |
| 1004 | pub fn lessThan(ctx: void, lhs: InitFunc, rhs: InitFunc) bool { | |
| 901 | 1005 | _ = ctx; |
| 902 | 1006 | if (lhs.priority == rhs.priority) { |
| 903 | 1007 | return @intFromEnum(lhs.function_index) < @intFromEnum(rhs.function_index); |
| ... | ... | @@ -1237,18 +1341,19 @@ pub fn deinit(wasm: *Wasm) void { |
| 1237 | 1341 | wasm.object_comdat_symbols.deinit(gpa); |
| 1238 | 1342 | wasm.objects.deinit(gpa); |
| 1239 | 1343 | |
| 1240 | wasm.atoms.deinit(gpa); | |
| 1241 | ||
| 1242 | 1344 | wasm.synthetic_symbols.deinit(gpa); |
| 1243 | wasm.globals.deinit(gpa); | |
| 1244 | 1345 | wasm.undefs.deinit(gpa); |
| 1245 | 1346 | wasm.discarded.deinit(gpa); |
| 1246 | 1347 | wasm.segments.deinit(gpa); |
| 1247 | 1348 | wasm.segment_info.deinit(gpa); |
| 1248 | 1349 | |
| 1249 | wasm.global_imports.deinit(gpa); | |
| 1250 | 1350 | wasm.func_types.deinit(gpa); |
| 1351 | wasm.function_exports.deinit(gpa); | |
| 1352 | wasm.function_imports.deinit(gpa); | |
| 1251 | 1353 | wasm.functions.deinit(gpa); |
| 1354 | wasm.globals.deinit(gpa); | |
| 1355 | wasm.global_imports.deinit(gpa); | |
| 1356 | wasm.table_imports.deinit(gpa); | |
| 1252 | 1357 | wasm.output_globals.deinit(gpa); |
| 1253 | 1358 | wasm.exports.deinit(gpa); |
| 1254 | 1359 | |
| ... | ... | @@ -1340,13 +1445,19 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index |
| 1340 | 1445 | |
| 1341 | 1446 | if (!nav_init.typeOf(zcu).hasRuntimeBits(zcu)) { |
| 1342 | 1447 | _ = wasm.imports.swapRemove(nav_index); |
| 1343 | _ = wasm.navs.swapRemove(nav_index); // TODO reclaim resources | |
| 1448 | if (wasm.navs.swapRemove(nav_index)) |old| { | |
| 1449 | _ = old; | |
| 1450 | @panic("TODO reclaim resources"); | |
| 1451 | } | |
| 1344 | 1452 | return; |
| 1345 | 1453 | } |
| 1346 | 1454 | |
| 1347 | 1455 | if (is_extern) { |
| 1348 | 1456 | try wasm.imports.put(nav_index, {}); |
| 1349 | _ = wasm.navs.swapRemove(nav_index); // TODO reclaim resources | |
| 1457 | if (wasm.navs.swapRemove(nav_index)) |old| { | |
| 1458 | _ = old; | |
| 1459 | @panic("TODO reclaim resources"); | |
| 1460 | } | |
| 1350 | 1461 | return; |
| 1351 | 1462 | } |
| 1352 | 1463 | |
| ... | ... | @@ -1528,7 +1639,8 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v |
| 1528 | 1639 | } |
| 1529 | 1640 | } |
| 1530 | 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 | 1644 | wasm.function_exports_len = @intCast(wasm.function_exports.items.len); |
| 1533 | 1645 | |
| 1534 | 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 | 1650 | } |
| 1539 | 1651 | } |
| 1540 | 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 | 1655 | wasm.global_exports_len = @intCast(wasm.global_exports.items.len); |
| 1543 | 1656 | |
| 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 | 1658 | if (import.flags.isIncluded(rdynamic)) { |
| 1546 | try markTable(wasm, name, import, @enumFromInt(i)); | |
| 1659 | try markTable(wasm, import.name, import, @enumFromInt(i)); | |
| 1547 | 1660 | continue; |
| 1548 | 1661 | } |
| 1549 | 1662 | } |
| ... | ... | @@ -1581,7 +1694,7 @@ fn markFunction( |
| 1581 | 1694 | import.resolution = .__wasm_init_tls; |
| 1582 | 1695 | wasm.functions.putAssumeCapacity(.__wasm_init_tls, {}); |
| 1583 | 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 | 1699 | } else { |
| 1587 | 1700 | const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution); |
| ... | ... | @@ -1631,7 +1744,7 @@ fn markGlobal( |
| 1631 | 1744 | import.resolution = .__tls_size; |
| 1632 | 1745 | wasm.globals.putAssumeCapacity(.__tls_size, {}); |
| 1633 | 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 | 1749 | } else { |
| 1637 | 1750 | const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution); |
| ... | ... | @@ -1663,7 +1776,7 @@ fn markTable( |
| 1663 | 1776 | import.resolution = .__indirect_function_table; |
| 1664 | 1777 | wasm.tables.putAssumeCapacity(.__indirect_function_table, {}); |
| 1665 | 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 | 1781 | } else { |
| 1669 | 1782 | wasm.tables.putAssumeCapacity(import.resolution, {}); |
| ... | ... | @@ -1722,7 +1835,6 @@ pub fn flushModule( |
| 1722 | 1835 | defer sub_prog_node.end(); |
| 1723 | 1836 | |
| 1724 | 1837 | wasm.flush_buffer.clear(); |
| 1725 | defer wasm.flush_buffer.subsequent = true; | |
| 1726 | 1838 | return wasm.flush_buffer.finish(wasm, arena); |
| 1727 | 1839 | } |
| 1728 | 1840 |
src/link/Wasm/Flush.zig+32-35| ... | ... | @@ -39,27 +39,17 @@ const DataSegmentIndex = enum(u32) { |
| 39 | 39 | |
| 40 | 40 | pub fn clear(f: *Flush) void { |
| 41 | 41 | f.binary_bytes.clearRetainingCapacity(); |
| 42 | f.function_imports.clearRetainingCapacity(); | |
| 43 | f.global_imports.clearRetainingCapacity(); | |
| 44 | f.functions.clearRetainingCapacity(); | |
| 45 | f.globals.clearRetainingCapacity(); | |
| 46 | 42 | f.data_segments.clearRetainingCapacity(); |
| 47 | 43 | f.data_segment_groups.clearRetainingCapacity(); |
| 48 | 44 | f.indirect_function_table.clearRetainingCapacity(); |
| 49 | f.function_exports.clearRetainingCapacity(); | |
| 50 | 45 | f.global_exports.clearRetainingCapacity(); |
| 51 | 46 | } |
| 52 | 47 | |
| 53 | 48 | pub fn deinit(f: *Flush, gpa: Allocator) void { |
| 54 | 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 | 50 | f.data_segments.deinit(gpa); |
| 60 | 51 | f.data_segment_groups.deinit(gpa); |
| 61 | 52 | f.indirect_function_table.deinit(gpa); |
| 62 | f.function_exports.deinit(gpa); | |
| 63 | 53 | f.global_exports.deinit(gpa); |
| 64 | 54 | f.* = undefined; |
| 65 | 55 | } |
| ... | ... | @@ -79,28 +69,32 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void { |
| 79 | 69 | |
| 80 | 70 | if (wasm.any_exports_updated) { |
| 81 | 71 | wasm.any_exports_updated = false; |
| 72 | ||
| 82 | 73 | wasm.function_exports.shrinkRetainingCapacity(wasm.function_exports_len); |
| 83 | 74 | wasm.global_exports.shrinkRetainingCapacity(wasm.global_exports_len); |
| 84 | 75 | |
| 85 | 76 | const entry_name = if (wasm.entry_resolution.isNavOrUnresolved(wasm)) wasm.entry_name else .none; |
| 86 | 77 | |
| 87 | 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 | 82 | for (wasm.nav_exports.keys()) |*nav_export| { |
| 89 | 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)); | |
| 91 | if (nav_export.name.toOptional() == entry_name) { | |
| 92 | wasm.entry_resolution = .pack(wasm, .{ .nav = nav_export.nav_index }); | |
| 93 | } else { | |
| 94 | f.missing_exports.swapRemove(nav_export.name); | |
| 95 | } | |
| 84 | try wasm.function_exports.append(gpa, Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?); | |
| 85 | _ = f.missing_exports.swapRemove(nav_export.name); | |
| 86 | _ = wasm.function_imports.swapRemove(nav_export.name); | |
| 87 | ||
| 88 | if (nav_export.name.toOptional() == entry_name) | |
| 89 | wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index); | |
| 96 | 90 | } else { |
| 97 | try wasm.global_exports.append(gpa, .fromNav(nav_export.nav_index)); | |
| 98 | f.missing_exports.swapRemove(nav_export.name); | |
| 91 | try wasm.global_exports.append(gpa, Wasm.GlobalIndex.fromIpNav(wasm, nav_export.nav_index).?); | |
| 92 | _ = f.missing_exports.swapRemove(nav_export.name); | |
| 93 | _ = wasm.global_imports.swapRemove(nav_export.name); | |
| 99 | 94 | } |
| 100 | 95 | } |
| 101 | 96 | |
| 102 | 97 | for (f.missing_exports.keys()) |exp_name| { |
| 103 | if (exp_name != .none) continue; | |
| 104 | 98 | diags.addError("manually specified export name '{s}' undefined", .{exp_name.slice(wasm)}); |
| 105 | 99 | } |
| 106 | 100 | |
| ... | ... | @@ -112,28 +106,31 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void { |
| 112 | 106 | } |
| 113 | 107 | |
| 114 | 108 | if (!allow_undefined) { |
| 115 | for (wasm.function_imports.keys()) |function_import_id| { | |
| 116 | const name, const src_loc = function_import_id.nameAndLoc(wasm); | |
| 117 | diags.addSrcError(src_loc, "undefined function: {s}", .{name.slice(wasm)}); | |
| 109 | for (wasm.function_imports.keys(), wasm.function_imports.values()) |name, function_import_id| { | |
| 110 | const src_loc = function_import_id.sourceLocation(wasm); | |
| 111 | src_loc.addError(wasm, "undefined function: {s}", .{name.slice(wasm)}); | |
| 118 | 112 | } |
| 119 | for (wasm.global_imports.keys()) |global_import_id| { | |
| 120 | const name, const src_loc = global_import_id.nameAndLoc(wasm); | |
| 121 | diags.addSrcError(src_loc, "undefined global: {s}", .{name.slice(wasm)}); | |
| 113 | for (wasm.global_imports.keys(), wasm.global_imports.values()) |name, global_import_id| { | |
| 114 | const src_loc = global_import_id.sourceLocation(wasm); | |
| 115 | src_loc.addError(wasm, "undefined global: {s}", .{name.slice(wasm)}); | |
| 122 | 116 | } |
| 123 | for (wasm.table_imports.keys()) |table_import_id| { | |
| 124 | const name, const src_loc = table_import_id.nameAndLoc(wasm); | |
| 125 | diags.addSrcError(src_loc, "undefined table: {s}", .{name.slice(wasm)}); | |
| 117 | for (wasm.table_imports.keys(), wasm.table_imports.values()) |name, table_import_id| { | |
| 118 | const src_loc = table_import_id.ptr(wasm).source_location; | |
| 119 | src_loc.addError(wasm, "undefined table: {s}", .{name.slice(wasm)}); | |
| 126 | 120 | } |
| 127 | 121 | } |
| 128 | 122 | |
| 129 | 123 | if (diags.hasErrors()) return error.LinkFailure; |
| 130 | 124 | |
| 125 | wasm.functions.shrinkRetainingCapacity(wasm.functions_len); | |
| 126 | wasm.globals.shrinkRetainingCapacity(wasm.globals_len); | |
| 127 | ||
| 131 | 128 | // TODO only include init functions for objects with must_link=true or |
| 132 | 129 | // which have any alive functions inside them. |
| 133 | 130 | if (wasm.object_init_funcs.items.len > 0) { |
| 134 | 131 | // Zig has no constructors so these are only for object file inputs. |
| 135 | 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 | } |
| 138 | 135 | |
| 139 | 136 | var any_passive_inits = false; |
| ... | ... | @@ -149,7 +146,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void { |
| 149 | 146 | }); |
| 150 | 147 | } |
| 151 | 148 | |
| 152 | try f.functions.ensureUnusedCapacity(gpa, 3); | |
| 149 | try wasm.functions.ensureUnusedCapacity(gpa, 3); | |
| 153 | 150 | |
| 154 | 151 | // Passive segments are used to avoid memory being reinitialized on each |
| 155 | 152 | // 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 | 154 | // We also initialize bss segments (using memory.fill) as part of this |
| 158 | 155 | // function. |
| 159 | 156 | if (any_passive_inits) { |
| 160 | f.functions.putAssumeCapacity(.__wasm_init_memory, {}); | |
| 157 | wasm.functions.putAssumeCapacity(.__wasm_init_memory, {}); | |
| 161 | 158 | } |
| 162 | 159 | |
| 163 | 160 | // When we have TLS GOT entries and shared memory is enabled, |
| 164 | 161 | // we must perform runtime relocations or else we don't create the function. |
| 165 | 162 | if (shared_memory) { |
| 166 | if (f.need_tls_relocs) f.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {}); | |
| 167 | f.functions.putAssumeCapacity(gpa, .__wasm_init_tls, {}); | |
| 163 | if (f.need_tls_relocs) wasm.functions.putAssumeCapacity(.__wasm_apply_global_tls_relocs, {}); | |
| 164 | wasm.functions.putAssumeCapacity(gpa, .__wasm_init_tls, {}); | |
| 168 | 165 | } |
| 169 | 166 | |
| 170 | 167 | // Sort order: |
| ... | ... | @@ -611,11 +608,11 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) anyerror!void { |
| 611 | 608 | } |
| 612 | 609 | |
| 613 | 610 | // Code section. |
| 614 | if (f.functions.count() != 0) { | |
| 611 | if (wasm.functions.count() != 0) { | |
| 615 | 612 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); |
| 616 | 613 | const start_offset = binary_bytes.items.len - 5; // minus 5 so start offset is 5 to include entry count |
| 617 | 614 | |
| 618 | for (f.functions.keys()) |resolution| switch (resolution.unpack()) { | |
| 615 | for (wasm.functions.keys()) |resolution| switch (resolution.unpack()) { | |
| 619 | 616 | .unresolved => unreachable, |
| 620 | 617 | .__wasm_apply_global_tls_relocs => @panic("TODO lower __wasm_apply_global_tls_relocs"), |
| 621 | 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 | 26 | /// (or therefore missing) and must generate an error when another object uses |
| 27 | 27 | /// features that are not supported by the other. |
| 28 | 28 | features: Wasm.Feature.Set, |
| 29 | /// Points into Wasm functions | |
| 29 | /// Points into Wasm object_functions | |
| 30 | 30 | functions: RelativeSlice, |
| 31 | /// Points into Wasm object_globals_imports | |
| 32 | globals_imports: RelativeSlice, | |
| 33 | /// Points into Wasm object_tables_imports | |
| 34 | tables_imports: RelativeSlice, | |
| 31 | /// Points into Wasm object_function_imports | |
| 32 | function_imports: RelativeSlice, | |
| 33 | /// Points into Wasm object_global_imports | |
| 34 | global_imports: RelativeSlice, | |
| 35 | /// Points into Wasm object_table_imports | |
| 36 | table_imports: RelativeSlice, | |
| 35 | 37 | /// Points into Wasm object_custom_segments |
| 36 | 38 | custom_segments: RelativeSlice, |
| 37 | 39 | /// For calculating local section index from `Wasm.SectionIndex`. |
| ... | ... | @@ -180,13 +182,13 @@ fn parse( |
| 180 | 182 | |
| 181 | 183 | const data_segment_start: u32 = @intCast(wasm.object_data_segments.items.len); |
| 182 | 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 | 185 | const functions_start: u32 = @intCast(wasm.object_functions.items.len); |
| 185 | 186 | const tables_start: u32 = @intCast(wasm.object_tables.items.len); |
| 186 | 187 | const memories_start: u32 = @intCast(wasm.object_memories.items.len); |
| 187 | 188 | const globals_start: u32 = @intCast(wasm.object_globals.items.len); |
| 188 | 189 | const init_funcs_start: u32 = @intCast(wasm.object_init_funcs.items.len); |
| 189 | 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 | 192 | const global_imports_start: u32 = @intCast(wasm.object_global_imports.items.len); |
| 191 | 193 | const table_imports_start: u32 = @intCast(wasm.object_table_imports.items.len); |
| 192 | 194 | const local_section_index_base = wasm.object_total_sections; |
| ... | ... | @@ -504,7 +506,7 @@ fn parse( |
| 504 | 506 | switch (kind) { |
| 505 | 507 | .function => { |
| 506 | 508 | const function, pos = readLeb(u32, bytes, pos); |
| 507 | try ss.function_imports.append(gpa, .{ | |
| 509 | try ss.func_imports.append(gpa, .{ | |
| 508 | 510 | .module_name = interned_module_name, |
| 509 | 511 | .name = interned_name, |
| 510 | 512 | .index = function, |
| ... | ... | @@ -854,13 +856,13 @@ fn parse( |
| 854 | 856 | .archive_member_name = archive_member_name, |
| 855 | 857 | .start_function = start_function, |
| 856 | 858 | .features = features, |
| 857 | .imports = .{ | |
| 858 | .off = imports_start, | |
| 859 | .len = @intCast(wasm.object_imports.items.len - imports_start), | |
| 860 | }, | |
| 861 | 859 | .functions = .{ |
| 862 | 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 | 867 | .tables = .{ |
| 866 | 868 | .off = tables_start, |
| ... | ... | @@ -870,9 +872,17 @@ fn parse( |
| 870 | 872 | .off = memories_start, |
| 871 | 873 | .len = @intCast(wasm.object_memories.items.len - memories_start), |
| 872 | 874 | }, |
| 873 | .globals = .{ | |
| 874 | .off = globals_start, | |
| 875 | .len = @intCast(wasm.object_globals.items.len - globals_start), | |
| 875 | .function_imports = .{ | |
| 876 | .off = function_imports_start, | |
| 877 | .len = @intCast(wasm.object_function_imports.items.len - function_imports_start), | |
| 878 | }, | |
| 879 | .global_imports = .{ | |
| 880 | .off = global_imports_start, | |
| 881 | .len = @intCast(wasm.object_global_imports.items.len - global_imports_start), | |
| 882 | }, | |
| 883 | .table_imports = .{ | |
| 884 | .off = table_imports_start, | |
| 885 | .len = @intCast(wasm.object_table_imports.items.len - table_imports_start), | |
| 876 | 886 | }, |
| 877 | 887 | .init_funcs = .{ |
| 878 | 888 | .off = init_funcs_start, |