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