| author | |
| committer | |
| log | 54e4a3456ce2d5a497a166b94737fe5407052921 |
| tree | 28721a6cfc8d522d59c98b8583c53a33b04aa94b |
| parent | 22b0eea3c0a2d2088ea6823d1de4ea5d9da6260d |
26 files changed, 489 insertions(+), 358 deletions(-)
lib/std/Io/File.zig+8-1| ... | ... | @@ -494,7 +494,14 @@ pub const WritePositionalError = Writer.Error || error{Unseekable}; |
| 494 | 494 | /// See also: |
| 495 | 495 | /// * `writer` |
| 496 | 496 | pub fn writePositional(file: File, io: Io, buffer: []const []const u8, offset: u64) WritePositionalError!usize { |
| 497 | return io.vtable.fileWritePositional(io.userdata, file, buffer, offset); | |
| 497 | return io.vtable.fileWritePositional(io.userdata, file, &.{}, buffer, 1, offset); | |
| 498 | } | |
| 499 | ||
| 500 | /// Equivalent to creating a positional writer, writing `bytes`, and then flushing. | |
| 501 | pub fn writePositionalAll(file: File, io: Io, bytes: []const u8, offset: u64) WritePositionalError!void { | |
| 502 | var index: usize = 0; | |
| 503 | while (index < bytes.len) | |
| 504 | index += try io.vtable.fileWritePositional(io.userdata, file, &.{}, &.{bytes[index..]}, 1, offset + index); | |
| 498 | 505 | } |
| 499 | 506 | |
| 500 | 507 | pub const SeekError = error{ |
src/link.zig+46-10| ... | ... | @@ -620,7 +620,7 @@ pub const File = struct { |
| 620 | 620 | emit.sub_path, std.crypto.random.int(u32), |
| 621 | 621 | }); |
| 622 | 622 | defer gpa.free(tmp_sub_path); |
| 623 | try emit.root_dir.handle.copyFile(emit.sub_path, emit.root_dir.handle, tmp_sub_path, .{}); | |
| 623 | try emit.root_dir.handle.copyFile(emit.sub_path, emit.root_dir.handle, tmp_sub_path, io, .{}); | |
| 624 | 624 | try emit.root_dir.handle.rename(tmp_sub_path, emit.root_dir.handle, emit.sub_path, io); |
| 625 | 625 | switch (builtin.os.tag) { |
| 626 | 626 | .linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| { |
| ... | ... | @@ -852,10 +852,12 @@ pub const File = struct { |
| 852 | 852 | } |
| 853 | 853 | } |
| 854 | 854 | |
| 855 | pub fn releaseLock(self: *File) void { | |
| 856 | if (self.lock) |*lock| { | |
| 857 | lock.release(); | |
| 858 | self.lock = null; | |
| 855 | pub fn releaseLock(base: *File) void { | |
| 856 | const comp = base.comp; | |
| 857 | const io = comp.io; | |
| 858 | if (base.lock) |*lock| { | |
| 859 | lock.release(io); | |
| 860 | base.lock = null; | |
| 859 | 861 | } |
| 860 | 862 | } |
| 861 | 863 | |
| ... | ... | @@ -908,6 +910,7 @@ pub const File = struct { |
| 908 | 910 | /// `arena` has the lifetime of the call to `Compilation.update`. |
| 909 | 911 | pub fn flush(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { |
| 910 | 912 | const comp = base.comp; |
| 913 | const io = comp.io; | |
| 911 | 914 | if (comp.clang_preprocessor_mode == .yes or comp.clang_preprocessor_mode == .pch) { |
| 912 | 915 | dev.check(.clang_command); |
| 913 | 916 | const emit = base.emit; |
| ... | ... | @@ -918,12 +921,19 @@ pub const File = struct { |
| 918 | 921 | assert(comp.c_object_table.count() == 1); |
| 919 | 922 | const the_key = comp.c_object_table.keys()[0]; |
| 920 | 923 | const cached_pp_file_path = the_key.status.success.object_path; |
| 921 | cached_pp_file_path.root_dir.handle.copyFile(cached_pp_file_path.sub_path, emit.root_dir.handle, emit.sub_path, .{}) catch |err| { | |
| 924 | Io.Dir.copyFile( | |
| 925 | cached_pp_file_path.root_dir.handle, | |
| 926 | cached_pp_file_path.sub_path, | |
| 927 | emit.root_dir.handle, | |
| 928 | emit.sub_path, | |
| 929 | io, | |
| 930 | .{}, | |
| 931 | ) catch |err| { | |
| 922 | 932 | const diags = &base.comp.link_diags; |
| 923 | return diags.fail("failed to copy '{f}' to '{f}': {s}", .{ | |
| 933 | return diags.fail("failed to copy '{f}' to '{f}': {t}", .{ | |
| 924 | 934 | std.fmt.alt(@as(Path, cached_pp_file_path), .formatEscapeChar), |
| 925 | 935 | std.fmt.alt(@as(Path, emit), .formatEscapeChar), |
| 926 | @errorName(err), | |
| 936 | err, | |
| 927 | 937 | }); |
| 928 | 938 | }; |
| 929 | 939 | return; |
| ... | ... | @@ -1119,7 +1129,7 @@ pub const File = struct { |
| 1119 | 1129 | const size = std.math.cast(u32, stat.size) orelse return error.FileTooBig; |
| 1120 | 1130 | const buf = try gpa.alloc(u8, size); |
| 1121 | 1131 | defer gpa.free(buf); |
| 1122 | const n = try file.preadAll(buf, 0); | |
| 1132 | const n = try file.readPositionalAll(io, buf, 0); | |
| 1123 | 1133 | if (buf.len != n) return error.UnexpectedEndOfFile; |
| 1124 | 1134 | var ld_script = try LdScript.parse(gpa, diags, path, buf); |
| 1125 | 1135 | defer ld_script.deinit(gpa); |
| ... | ... | @@ -1184,6 +1194,32 @@ pub const File = struct { |
| 1184 | 1194 | } |
| 1185 | 1195 | } |
| 1186 | 1196 | |
| 1197 | /// Legacy function for old linker code | |
| 1198 | pub fn copyRangeAll(base: *File, old_offset: u64, new_offset: u64, size: u64) !void { | |
| 1199 | const comp = base.comp; | |
| 1200 | const io = comp.io; | |
| 1201 | const file = base.file.?; | |
| 1202 | return copyRangeAll2(io, file, file, old_offset, new_offset, size); | |
| 1203 | } | |
| 1204 | ||
| 1205 | /// Legacy function for old linker code | |
| 1206 | pub fn copyRangeAll2(io: Io, src_file: Io.File, dst_file: Io.File, old_offset: u64, new_offset: u64, size: u64) !void { | |
| 1207 | var write_buffer: [2048]u8 = undefined; | |
| 1208 | var file_reader = src_file.reader(io, &.{}); | |
| 1209 | file_reader.pos = old_offset; | |
| 1210 | var file_writer = dst_file.writer(io, &write_buffer); | |
| 1211 | file_writer.pos = new_offset; | |
| 1212 | const size_u = std.math.cast(usize, size) orelse return error.Overflow; | |
| 1213 | const n = file_writer.interface.sendFileAll(&file_reader, .limited(size_u)) catch |err| switch (err) { | |
| 1214 | error.ReadFailed => return file_reader.err.?, | |
| 1215 | error.WriteFailed => return file_writer.err.?, | |
| 1216 | }; | |
| 1217 | assert(n == size_u); | |
| 1218 | file_writer.interface.flush() catch |err| switch (err) { | |
| 1219 | error.WriteFailed => return file_writer.err.?, | |
| 1220 | }; | |
| 1221 | } | |
| 1222 | ||
| 1187 | 1223 | pub const Tag = enum { |
| 1188 | 1224 | coff2, |
| 1189 | 1225 | elf, |
| ... | ... | @@ -1243,7 +1279,7 @@ pub const File = struct { |
| 1243 | 1279 | // with 0o755 permissions, but it works appropriately if the system is configured |
| 1244 | 1280 | // more leniently. As another data point, C's fopen seems to open files with the |
| 1245 | 1281 | // 666 mode. |
| 1246 | const executable_mode: Io.FilePermissions = if (builtin.target.os.tag == .windows) | |
| 1282 | const executable_mode: Io.File.Permissions = if (builtin.target.os.tag == .windows) | |
| 1247 | 1283 | .default_file |
| 1248 | 1284 | else |
| 1249 | 1285 | .fromMode(0o777); |
src/link/Coff.zig+24-23| ... | ... | @@ -1,3 +1,22 @@ |
| 1 | const Coff = @This(); | |
| 2 | ||
| 3 | const builtin = @import("builtin"); | |
| 4 | const native_endian = builtin.cpu.arch.endian(); | |
| 5 | ||
| 6 | const std = @import("std"); | |
| 7 | const assert = std.debug.assert; | |
| 8 | const log = std.log.scoped(.link); | |
| 9 | ||
| 10 | const codegen = @import("../codegen.zig"); | |
| 11 | const Compilation = @import("../Compilation.zig"); | |
| 12 | const InternPool = @import("../InternPool.zig"); | |
| 13 | const link = @import("../link.zig"); | |
| 14 | const MappedFile = @import("MappedFile.zig"); | |
| 15 | const target_util = @import("../target.zig"); | |
| 16 | const Type = @import("../Type.zig"); | |
| 17 | const Value = @import("../Value.zig"); | |
| 18 | const Zcu = @import("../Zcu.zig"); | |
| 19 | ||
| 1 | 20 | base: link.File, |
| 2 | 21 | mf: MappedFile, |
| 3 | 22 | nodes: std.MultiArrayList(Node), |
| ... | ... | @@ -1729,22 +1748,20 @@ pub fn flush( |
| 1729 | 1748 | const comp = coff.base.comp; |
| 1730 | 1749 | if (comp.compiler_rt_dyn_lib) |crt_file| { |
| 1731 | 1750 | const gpa = comp.gpa; |
| 1751 | const io = comp.io; | |
| 1732 | 1752 | const compiler_rt_sub_path = try std.fs.path.join(gpa, &.{ |
| 1733 | 1753 | std.fs.path.dirname(coff.base.emit.sub_path) orelse "", |
| 1734 | 1754 | std.fs.path.basename(crt_file.full_object_path.sub_path), |
| 1735 | 1755 | }); |
| 1736 | 1756 | defer gpa.free(compiler_rt_sub_path); |
| 1737 | crt_file.full_object_path.root_dir.handle.copyFile( | |
| 1757 | std.Io.Dir.copyFile( | |
| 1758 | crt_file.full_object_path.root_dir.handle, | |
| 1738 | 1759 | crt_file.full_object_path.sub_path, |
| 1739 | 1760 | coff.base.emit.root_dir.handle, |
| 1740 | 1761 | compiler_rt_sub_path, |
| 1762 | io, | |
| 1741 | 1763 | .{}, |
| 1742 | ) catch |err| switch (err) { | |
| 1743 | else => |e| return comp.link_diags.fail("Copy '{s}' failed: {s}", .{ | |
| 1744 | compiler_rt_sub_path, | |
| 1745 | @errorName(e), | |
| 1746 | }), | |
| 1747 | }; | |
| 1764 | ) catch |err| return comp.link_diags.fail("copy '{s}' failed: {t}", .{ compiler_rt_sub_path, err }); | |
| 1748 | 1765 | } |
| 1749 | 1766 | } |
| 1750 | 1767 | |
| ... | ... | @@ -2461,19 +2478,3 @@ pub fn printNode( |
| 2461 | 2478 | } |
| 2462 | 2479 | } |
| 2463 | 2480 | } |
| 2464 | ||
| 2465 | const assert = std.debug.assert; | |
| 2466 | const builtin = @import("builtin"); | |
| 2467 | const codegen = @import("../codegen.zig"); | |
| 2468 | const Compilation = @import("../Compilation.zig"); | |
| 2469 | const Coff = @This(); | |
| 2470 | const InternPool = @import("../InternPool.zig"); | |
| 2471 | const link = @import("../link.zig"); | |
| 2472 | const log = std.log.scoped(.link); | |
| 2473 | const MappedFile = @import("MappedFile.zig"); | |
| 2474 | const native_endian = builtin.cpu.arch.endian(); | |
| 2475 | const std = @import("std"); | |
| 2476 | const target_util = @import("../target.zig"); | |
| 2477 | const Type = @import("../Type.zig"); | |
| 2478 | const Value = @import("../Value.zig"); | |
| 2479 | const Zcu = @import("../Zcu.zig"); |
src/link/Dwarf.zig+35-20| ... | ... | @@ -48,6 +48,7 @@ pub const UpdateError = error{ |
| 48 | 48 | EndOfStream, |
| 49 | 49 | Underflow, |
| 50 | 50 | UnexpectedEndOfFile, |
| 51 | NonResizable, | |
| 51 | 52 | } || |
| 52 | 53 | codegen.GenerateSymbolError || |
| 53 | 54 | Io.File.OpenError || |
| ... | ... | @@ -155,11 +156,14 @@ const DebugInfo = struct { |
| 155 | 156 | |
| 156 | 157 | fn declAbbrevCode(debug_info: *DebugInfo, unit: Unit.Index, entry: Entry.Index) !AbbrevCode { |
| 157 | 158 | const dwarf: *Dwarf = @fieldParentPtr("debug_info", debug_info); |
| 159 | const comp = dwarf.bin_file.comp; | |
| 160 | const io = comp.io; | |
| 158 | 161 | const unit_ptr = debug_info.section.getUnit(unit); |
| 159 | 162 | const entry_ptr = unit_ptr.getEntry(entry); |
| 160 | 163 | if (entry_ptr.len < AbbrevCode.decl_bytes) return .null; |
| 161 | 164 | var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined; |
| 162 | if (try dwarf.getFile().?.preadAll( | |
| 165 | if (try dwarf.getFile().?.readPositionalAll( | |
| 166 | io, | |
| 163 | 167 | &abbrev_code_buf, |
| 164 | 168 | debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off, |
| 165 | 169 | ) != abbrev_code_buf.len) return error.InputOutput; |
| ... | ... | @@ -639,13 +643,10 @@ const Unit = struct { |
| 639 | 643 | |
| 640 | 644 | fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void { |
| 641 | 645 | if (unit.off == new_off) return; |
| 642 | const n = try dwarf.getFile().?.copyRangeAll( | |
| 643 | sec.off(dwarf) + unit.off, | |
| 644 | dwarf.getFile().?, | |
| 645 | sec.off(dwarf) + new_off, | |
| 646 | unit.len, | |
| 647 | ); | |
| 648 | if (n != unit.len) return error.InputOutput; | |
| 646 | const comp = dwarf.bin_file.comp; | |
| 647 | const io = comp.io; | |
| 648 | const file = dwarf.getFile().?; | |
| 649 | try link.File.copyRangeAll2(io, file, file, sec.off(dwarf) + unit.off, sec.off(dwarf) + new_off, unit.len); | |
| 649 | 650 | unit.off = new_off; |
| 650 | 651 | } |
| 651 | 652 | |
| ... | ... | @@ -675,10 +676,14 @@ const Unit = struct { |
| 675 | 676 | |
| 676 | 677 | fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void { |
| 677 | 678 | assert(contents.len == unit.header_len); |
| 678 | try dwarf.getFile().?.pwriteAll(contents, sec.off(dwarf) + unit.off); | |
| 679 | const comp = dwarf.bin_file.comp; | |
| 680 | const io = comp.io; | |
| 681 | try dwarf.getFile().?.writePositionalAll(io, contents, sec.off(dwarf) + unit.off); | |
| 679 | 682 | } |
| 680 | 683 | |
| 681 | 684 | fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void { |
| 685 | const comp = dwarf.bin_file.comp; | |
| 686 | const io = comp.io; | |
| 682 | 687 | const start = unit.off + unit.header_len + if (unit.last.unwrap()) |last_entry| end: { |
| 683 | 688 | const last_entry_ptr = unit.getEntry(last_entry); |
| 684 | 689 | break :end last_entry_ptr.off + last_entry_ptr.len; |
| ... | ... | @@ -708,7 +713,7 @@ const Unit = struct { |
| 708 | 713 | assert(fw.end == extended_op_bytes + op_len_bytes); |
| 709 | 714 | fw.writeByte(DW.LNE.padding) catch unreachable; |
| 710 | 715 | assert(fw.end >= unit.trailer_len and fw.end <= len); |
| 711 | return dwarf.getFile().?.pwriteAll(fw.buffered(), sec.off(dwarf) + start); | |
| 716 | return dwarf.getFile().?.writePositionalAll(io, fw.buffered(), sec.off(dwarf) + start); | |
| 712 | 717 | } |
| 713 | 718 | var trailer_aw: Writer.Allocating = try .initCapacity(dwarf.gpa, len); |
| 714 | 719 | defer trailer_aw.deinit(); |
| ... | ... | @@ -768,7 +773,7 @@ const Unit = struct { |
| 768 | 773 | assert(tw.end == unit.trailer_len); |
| 769 | 774 | tw.splatByteAll(fill_byte, len - unit.trailer_len) catch unreachable; |
| 770 | 775 | assert(tw.end == len); |
| 771 | try dwarf.getFile().?.pwriteAll(trailer_aw.written(), sec.off(dwarf) + start); | |
| 776 | try dwarf.getFile().?.writePositionalAll(io, trailer_aw.written(), sec.off(dwarf) + start); | |
| 772 | 777 | } |
| 773 | 778 | |
| 774 | 779 | fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { |
| ... | ... | @@ -854,6 +859,8 @@ const Entry = struct { |
| 854 | 859 | dwarf: *Dwarf, |
| 855 | 860 | ) (UpdateError || Writer.Error)!void { |
| 856 | 861 | assert(entry.len > 0); |
| 862 | const comp = dwarf.bin_file.comp; | |
| 863 | const io = comp.io; | |
| 857 | 864 | const start = entry.off + entry.len; |
| 858 | 865 | if (sec == &dwarf.debug_frame.section) { |
| 859 | 866 | const len = if (entry.next.unwrap()) |next_entry| |
| ... | ... | @@ -863,11 +870,11 @@ const Entry = struct { |
| 863 | 870 | var unit_len_buf: [8]u8 = undefined; |
| 864 | 871 | const unit_len_bytes = unit_len_buf[0..dwarf.sectionOffsetBytes()]; |
| 865 | 872 | dwarf.writeInt(unit_len_bytes, len - dwarf.unitLengthBytes()); |
| 866 | try dwarf.getFile().?.pwriteAll(unit_len_bytes, sec.off(dwarf) + unit.off + unit.header_len + entry.off); | |
| 873 | try dwarf.getFile().?.writePositionalAll(io, unit_len_bytes, sec.off(dwarf) + unit.off + unit.header_len + entry.off); | |
| 867 | 874 | const buf = try dwarf.gpa.alloc(u8, len - entry.len); |
| 868 | 875 | defer dwarf.gpa.free(buf); |
| 869 | 876 | @memset(buf, DW.CFA.nop); |
| 870 | try dwarf.getFile().?.pwriteAll(buf, sec.off(dwarf) + unit.off + unit.header_len + start); | |
| 877 | try dwarf.getFile().?.writePositionalAll(io, buf, sec.off(dwarf) + unit.off + unit.header_len + start); | |
| 871 | 878 | return; |
| 872 | 879 | } |
| 873 | 880 | const len = unit.getEntry(entry.next.unwrap() orelse return).off - start; |
| ... | ... | @@ -926,7 +933,7 @@ const Entry = struct { |
| 926 | 933 | }, |
| 927 | 934 | } else assert(!sec.pad_entries_to_ideal and len == 0); |
| 928 | 935 | assert(fw.end <= len); |
| 929 | try dwarf.getFile().?.pwriteAll(fw.buffered(), sec.off(dwarf) + unit.off + unit.header_len + start); | |
| 936 | try dwarf.getFile().?.writePositionalAll(io, fw.buffered(), sec.off(dwarf) + unit.off + unit.header_len + start); | |
| 930 | 937 | } |
| 931 | 938 | |
| 932 | 939 | fn resize( |
| ... | ... | @@ -969,11 +976,13 @@ const Entry = struct { |
| 969 | 976 | |
| 970 | 977 | fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void { |
| 971 | 978 | assert(contents.len == entry_ptr.len); |
| 972 | try dwarf.getFile().?.pwriteAll(contents, sec.off(dwarf) + unit.off + unit.header_len + entry_ptr.off); | |
| 979 | const comp = dwarf.bin_file.comp; | |
| 980 | const io = comp.io; | |
| 981 | try dwarf.getFile().?.writePositionalAll(io, contents, sec.off(dwarf) + unit.off + unit.header_len + entry_ptr.off); | |
| 973 | 982 | if (false) { |
| 974 | 983 | const buf = try dwarf.gpa.alloc(u8, sec.len); |
| 975 | 984 | defer dwarf.gpa.free(buf); |
| 976 | _ = try dwarf.getFile().?.preadAll(buf, sec.off(dwarf)); | |
| 985 | _ = try dwarf.getFile().?.readPositionalAll(io, buf, sec.off(dwarf)); | |
| 977 | 986 | log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{ |
| 978 | 987 | @intFromEnum(sec.first), |
| 979 | 988 | @intFromEnum(sec.last), |
| ... | ... | @@ -4702,6 +4711,8 @@ fn updateContainerTypeWriterError( |
| 4702 | 4711 | } |
| 4703 | 4712 | |
| 4704 | 4713 | pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index) UpdateError!void { |
| 4714 | const comp = dwarf.bin_file.comp; | |
| 4715 | const io = comp.io; | |
| 4705 | 4716 | const ip = &zcu.intern_pool; |
| 4706 | 4717 | |
| 4707 | 4718 | const inst_info = zir_index.resolveFull(ip).?; |
| ... | ... | @@ -4721,7 +4732,7 @@ pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedI |
| 4721 | 4732 | |
| 4722 | 4733 | const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return); |
| 4723 | 4734 | const entry = unit.getEntry(dwarf.decls.get(zir_index) orelse return); |
| 4724 | try dwarf.getFile().?.pwriteAll(&line_buf, dwarf.debug_info.section.off(dwarf) + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf)); | |
| 4735 | try dwarf.getFile().?.writePositionalAll(io, &line_buf, dwarf.debug_info.section.off(dwarf) + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf)); | |
| 4725 | 4736 | } |
| 4726 | 4737 | |
| 4727 | 4738 | pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void { |
| ... | ... | @@ -4758,6 +4769,8 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { |
| 4758 | 4769 | fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Error)!void { |
| 4759 | 4770 | const zcu = pt.zcu; |
| 4760 | 4771 | const ip = &zcu.intern_pool; |
| 4772 | const comp = dwarf.bin_file.comp; | |
| 4773 | const io = comp.io; | |
| 4761 | 4774 | |
| 4762 | 4775 | { |
| 4763 | 4776 | const type_gop = try dwarf.types.getOrPut(dwarf.gpa, .anyerror_type); |
| ... | ... | @@ -4977,7 +4990,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Erro |
| 4977 | 4990 | if (dwarf.debug_str.section.dirty) { |
| 4978 | 4991 | const contents = dwarf.debug_str.contents.items; |
| 4979 | 4992 | try dwarf.debug_str.section.resize(dwarf, contents.len); |
| 4980 | try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off(dwarf)); | |
| 4993 | try dwarf.getFile().?.writePositionalAll(io, contents, dwarf.debug_str.section.off(dwarf)); | |
| 4981 | 4994 | dwarf.debug_str.section.dirty = false; |
| 4982 | 4995 | } |
| 4983 | 4996 | if (dwarf.debug_line.section.dirty) { |
| ... | ... | @@ -5089,7 +5102,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Erro |
| 5089 | 5102 | if (dwarf.debug_line_str.section.dirty) { |
| 5090 | 5103 | const contents = dwarf.debug_line_str.contents.items; |
| 5091 | 5104 | try dwarf.debug_line_str.section.resize(dwarf, contents.len); |
| 5092 | try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off(dwarf)); | |
| 5105 | try dwarf.getFile().?.writePositionalAll(io, contents, dwarf.debug_line_str.section.off(dwarf)); | |
| 5093 | 5106 | dwarf.debug_line_str.section.dirty = false; |
| 5094 | 5107 | } |
| 5095 | 5108 | if (dwarf.debug_loclists.section.dirty) { |
| ... | ... | @@ -6411,9 +6424,11 @@ fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void { |
| 6411 | 6424 | } |
| 6412 | 6425 | |
| 6413 | 6426 | fn resolveReloc(dwarf: *Dwarf, source: u64, target: u64, size: u32) RelocError!void { |
| 6427 | const comp = dwarf.bin_file.comp; | |
| 6428 | const io = comp.io; | |
| 6414 | 6429 | var buf: [8]u8 = undefined; |
| 6415 | 6430 | dwarf.writeInt(buf[0..size], target); |
| 6416 | try dwarf.getFile().?.pwriteAll(buf[0..size], source); | |
| 6431 | try dwarf.getFile().?.writePositionalAll(io, buf[0..size], source); | |
| 6417 | 6432 | } |
| 6418 | 6433 | |
| 6419 | 6434 | fn unitLengthBytes(dwarf: *Dwarf) u32 { |
src/link/Elf.zig+31-44| ... | ... | @@ -582,14 +582,7 @@ pub fn growSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment: |
| 582 | 582 | new_offset, |
| 583 | 583 | }); |
| 584 | 584 | |
| 585 | const amt = try self.base.file.?.copyRangeAll( | |
| 586 | shdr.sh_offset, | |
| 587 | self.base.file.?, | |
| 588 | new_offset, | |
| 589 | existing_size, | |
| 590 | ); | |
| 591 | // TODO figure out what to about this error condition - how to communicate it up. | |
| 592 | if (amt != existing_size) return error.InputOutput; | |
| 585 | try self.base.copyRangeAll(shdr.sh_offset, new_offset, existing_size); | |
| 593 | 586 | |
| 594 | 587 | shdr.sh_offset = new_offset; |
| 595 | 588 | } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) { |
| ... | ... | @@ -745,7 +738,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void { |
| 745 | 738 | .res => unreachable, |
| 746 | 739 | .dso_exact => @panic("TODO"), |
| 747 | 740 | .object => |obj| try parseObject(self, obj), |
| 748 | .archive => |obj| try parseArchive(gpa, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj, is_static_lib), | |
| 741 | .archive => |obj| try parseArchive(gpa, io, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj, is_static_lib), | |
| 749 | 742 | .dso => |dso| try parseDso(gpa, io, diags, dso, &self.shared_objects, &self.files, target), |
| 750 | 743 | } |
| 751 | 744 | } |
| ... | ... | @@ -1055,9 +1048,11 @@ fn dumpArgvInit(self: *Elf, arena: Allocator) !void { |
| 1055 | 1048 | } |
| 1056 | 1049 | |
| 1057 | 1050 | pub fn openParseObjectReportingFailure(self: *Elf, path: Path) void { |
| 1058 | const diags = &self.base.comp.link_diags; | |
| 1059 | const obj = link.openObject(path, false, false) catch |err| { | |
| 1060 | switch (diags.failParse(path, "failed to open object: {s}", .{@errorName(err)})) { | |
| 1051 | const comp = self.base.comp; | |
| 1052 | const io = comp.io; | |
| 1053 | const diags = &comp.link_diags; | |
| 1054 | const obj = link.openObject(io, path, false, false) catch |err| { | |
| 1055 | switch (diags.failParse(path, "failed to open object: {t}", .{err})) { | |
| 1061 | 1056 | error.LinkFailure => return, |
| 1062 | 1057 | } |
| 1063 | 1058 | }; |
| ... | ... | @@ -1065,10 +1060,11 @@ pub fn openParseObjectReportingFailure(self: *Elf, path: Path) void { |
| 1065 | 1060 | } |
| 1066 | 1061 | |
| 1067 | 1062 | fn parseObjectReportingFailure(self: *Elf, obj: link.Input.Object) void { |
| 1068 | const diags = &self.base.comp.link_diags; | |
| 1063 | const comp = self.base.comp; | |
| 1064 | const diags = &comp.link_diags; | |
| 1069 | 1065 | self.parseObject(obj) catch |err| switch (err) { |
| 1070 | 1066 | error.LinkFailure => return, // already reported |
| 1071 | else => |e| diags.addParseError(obj.path, "failed to parse object: {s}", .{@errorName(e)}), | |
| 1067 | else => |e| diags.addParseError(obj.path, "failed to parse object: {t}", .{e}), | |
| 1072 | 1068 | }; |
| 1073 | 1069 | } |
| 1074 | 1070 | |
| ... | ... | @@ -1076,10 +1072,12 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void { |
| 1076 | 1072 | const tracy = trace(@src()); |
| 1077 | 1073 | defer tracy.end(); |
| 1078 | 1074 | |
| 1079 | const gpa = self.base.comp.gpa; | |
| 1080 | const diags = &self.base.comp.link_diags; | |
| 1081 | const target = &self.base.comp.root_mod.resolved_target.result; | |
| 1082 | const debug_fmt_strip = self.base.comp.config.debug_format == .strip; | |
| 1075 | const comp = self.base.comp; | |
| 1076 | const io = comp.io; | |
| 1077 | const gpa = comp.gpa; | |
| 1078 | const diags = &comp.link_diags; | |
| 1079 | const target = &comp.root_mod.resolved_target.result; | |
| 1080 | const debug_fmt_strip = comp.config.debug_format == .strip; | |
| 1083 | 1081 | const default_sym_version = self.default_sym_version; |
| 1084 | 1082 | const file_handles = &self.file_handles; |
| 1085 | 1083 | |
| ... | ... | @@ -1098,14 +1096,15 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void { |
| 1098 | 1096 | try self.objects.append(gpa, index); |
| 1099 | 1097 | |
| 1100 | 1098 | const object = self.file(index).?.object; |
| 1101 | try object.parseCommon(gpa, diags, obj.path, handle, target); | |
| 1099 | try object.parseCommon(gpa, io, diags, obj.path, handle, target); | |
| 1102 | 1100 | if (!self.base.isStaticLib()) { |
| 1103 | try object.parse(gpa, diags, obj.path, handle, target, debug_fmt_strip, default_sym_version); | |
| 1101 | try object.parse(gpa, io, diags, obj.path, handle, target, debug_fmt_strip, default_sym_version); | |
| 1104 | 1102 | } |
| 1105 | 1103 | } |
| 1106 | 1104 | |
| 1107 | 1105 | fn parseArchive( |
| 1108 | 1106 | gpa: Allocator, |
| 1107 | io: Io, | |
| 1109 | 1108 | diags: *Diags, |
| 1110 | 1109 | file_handles: *std.ArrayList(File.Handle), |
| 1111 | 1110 | files: *std.MultiArrayList(File.Entry), |
| ... | ... | @@ -1120,7 +1119,7 @@ fn parseArchive( |
| 1120 | 1119 | defer tracy.end(); |
| 1121 | 1120 | |
| 1122 | 1121 | const fh = try addFileHandle(gpa, file_handles, obj.file); |
| 1123 | var archive = try Archive.parse(gpa, diags, file_handles, obj.path, fh); | |
| 1122 | var archive = try Archive.parse(gpa, io, diags, file_handles, obj.path, fh); | |
| 1124 | 1123 | defer archive.deinit(gpa); |
| 1125 | 1124 | |
| 1126 | 1125 | const init_alive = if (is_static_lib) true else obj.must_link; |
| ... | ... | @@ -1131,9 +1130,9 @@ fn parseArchive( |
| 1131 | 1130 | const object = &files.items(.data)[index].object; |
| 1132 | 1131 | object.index = index; |
| 1133 | 1132 | object.alive = init_alive; |
| 1134 | try object.parseCommon(gpa, diags, obj.path, obj.file, target); | |
| 1133 | try object.parseCommon(gpa, io, diags, obj.path, obj.file, target); | |
| 1135 | 1134 | if (!is_static_lib) |
| 1136 | try object.parse(gpa, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version); | |
| 1135 | try object.parse(gpa, io, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version); | |
| 1137 | 1136 | try objects.append(gpa, index); |
| 1138 | 1137 | } |
| 1139 | 1138 | } |
| ... | ... | @@ -1153,7 +1152,7 @@ fn parseDso( |
| 1153 | 1152 | const handle = dso.file; |
| 1154 | 1153 | |
| 1155 | 1154 | const stat = Stat.fromFs(try handle.stat(io)); |
| 1156 | var header = try SharedObject.parseHeader(gpa, diags, dso.path, handle, stat, target); | |
| 1155 | var header = try SharedObject.parseHeader(gpa, io, diags, dso.path, handle, stat, target); | |
| 1157 | 1156 | defer header.deinit(gpa); |
| 1158 | 1157 | |
| 1159 | 1158 | const soname = header.soname() orelse dso.path.basename(); |
| ... | ... | @@ -1167,7 +1166,7 @@ fn parseDso( |
| 1167 | 1166 | |
| 1168 | 1167 | gop.value_ptr.* = index; |
| 1169 | 1168 | |
| 1170 | var parsed = try SharedObject.parse(gpa, &header, handle); | |
| 1169 | var parsed = try SharedObject.parse(gpa, io, &header, handle); | |
| 1171 | 1170 | errdefer parsed.deinit(gpa); |
| 1172 | 1171 | |
| 1173 | 1172 | const duped_path: Path = .{ |
| ... | ... | @@ -2897,13 +2896,7 @@ pub fn allocateAllocSections(self: *Elf) !void { |
| 2897 | 2896 | if (shdr.sh_offset > 0) { |
| 2898 | 2897 | // Get size actually commited to the output file. |
| 2899 | 2898 | const existing_size = self.sectionSize(shndx); |
| 2900 | const amt = try self.base.file.?.copyRangeAll( | |
| 2901 | shdr.sh_offset, | |
| 2902 | self.base.file.?, | |
| 2903 | new_offset, | |
| 2904 | existing_size, | |
| 2905 | ); | |
| 2906 | if (amt != existing_size) return error.InputOutput; | |
| 2899 | try self.base.copyRangeAll(shdr.sh_offset, new_offset, existing_size); | |
| 2907 | 2900 | } |
| 2908 | 2901 | |
| 2909 | 2902 | shdr.sh_offset = new_offset; |
| ... | ... | @@ -2939,13 +2932,7 @@ pub fn allocateNonAllocSections(self: *Elf) !void { |
| 2939 | 2932 | |
| 2940 | 2933 | if (shdr.sh_offset > 0) { |
| 2941 | 2934 | const existing_size = self.sectionSize(@intCast(shndx)); |
| 2942 | const amt = try self.base.file.?.copyRangeAll( | |
| 2943 | shdr.sh_offset, | |
| 2944 | self.base.file.?, | |
| 2945 | new_offset, | |
| 2946 | existing_size, | |
| 2947 | ); | |
| 2948 | if (amt != existing_size) return error.InputOutput; | |
| 2935 | try self.base.copyRangeAll(shdr.sh_offset, new_offset, existing_size); | |
| 2949 | 2936 | } |
| 2950 | 2937 | |
| 2951 | 2938 | shdr.sh_offset = new_offset; |
| ... | ... | @@ -4075,10 +4062,10 @@ fn fmtDumpState(self: *Elf, writer: *std.Io.Writer) std.Io.Writer.Error!void { |
| 4075 | 4062 | } |
| 4076 | 4063 | |
| 4077 | 4064 | /// Caller owns the memory. |
| 4078 | pub fn preadAllAlloc(allocator: Allocator, handle: Io.File, offset: u64, size: u64) ![]u8 { | |
| 4065 | pub fn preadAllAlloc(allocator: Allocator, io: Io, io_file: Io.File, offset: u64, size: u64) ![]u8 { | |
| 4079 | 4066 | const buffer = try allocator.alloc(u8, math.cast(usize, size) orelse return error.Overflow); |
| 4080 | 4067 | errdefer allocator.free(buffer); |
| 4081 | const amt = try handle.preadAll(buffer, offset); | |
| 4068 | const amt = try io_file.readPositionalAll(io, buffer, offset); | |
| 4082 | 4069 | if (amt != size) return error.InputOutput; |
| 4083 | 4070 | return buffer; |
| 4084 | 4071 | } |
| ... | ... | @@ -4444,10 +4431,10 @@ pub fn stringTableLookup(strtab: []const u8, off: u32) [:0]const u8 { |
| 4444 | 4431 | |
| 4445 | 4432 | pub fn pwriteAll(elf_file: *Elf, bytes: []const u8, offset: u64) error{LinkFailure}!void { |
| 4446 | 4433 | const comp = elf_file.base.comp; |
| 4434 | const io = comp.io; | |
| 4447 | 4435 | const diags = &comp.link_diags; |
| 4448 | elf_file.base.file.?.pwriteAll(bytes, offset) catch |err| { | |
| 4449 | return diags.fail("failed to write: {s}", .{@errorName(err)}); | |
| 4450 | }; | |
| 4436 | elf_file.base.file.?.writePositionalAll(io, bytes, offset) catch |err| | |
| 4437 | return diags.fail("failed to write: {t}", .{err}); | |
| 4451 | 4438 | } |
| 4452 | 4439 | |
| 4453 | 4440 | pub fn setLength(elf_file: *Elf, length: u64) error{LinkFailure}!void { |
src/link/Elf/Archive.zig+5-5| ... | ... | @@ -34,17 +34,17 @@ pub fn parse( |
| 34 | 34 | path: Path, |
| 35 | 35 | handle_index: File.HandleIndex, |
| 36 | 36 | ) !Archive { |
| 37 | const handle = file_handles.items[handle_index]; | |
| 37 | const file = file_handles.items[handle_index]; | |
| 38 | 38 | var pos: usize = 0; |
| 39 | 39 | { |
| 40 | 40 | var magic_buffer: [elf.ARMAG.len]u8 = undefined; |
| 41 | const n = try handle.preadAll(&magic_buffer, pos); | |
| 41 | const n = try file.readPositionalAll(io, &magic_buffer, pos); | |
| 42 | 42 | if (n != magic_buffer.len) return error.BadMagic; |
| 43 | 43 | if (!mem.eql(u8, &magic_buffer, elf.ARMAG)) return error.BadMagic; |
| 44 | 44 | pos += magic_buffer.len; |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | const size = (try handle.stat(io)).size; | |
| 47 | const size = (try file.stat(io)).size; | |
| 48 | 48 | |
| 49 | 49 | var objects: std.ArrayList(Object) = .empty; |
| 50 | 50 | defer objects.deinit(gpa); |
| ... | ... | @@ -55,7 +55,7 @@ pub fn parse( |
| 55 | 55 | while (pos < size) { |
| 56 | 56 | var hdr: elf.ar_hdr = undefined; |
| 57 | 57 | { |
| 58 | const n = try handle.preadAll(mem.asBytes(&hdr), pos); | |
| 58 | const n = try file.readPositionalAll(io, mem.asBytes(&hdr), pos); | |
| 59 | 59 | if (n != @sizeOf(elf.ar_hdr)) return error.UnexpectedEndOfFile; |
| 60 | 60 | } |
| 61 | 61 | pos += @sizeOf(elf.ar_hdr); |
| ... | ... | @@ -72,7 +72,7 @@ pub fn parse( |
| 72 | 72 | if (hdr.isSymtab() or hdr.isSymtab64()) continue; |
| 73 | 73 | if (hdr.isStrtab()) { |
| 74 | 74 | try strtab.resize(gpa, obj_size); |
| 75 | const amt = try handle.preadAll(strtab.items, pos); | |
| 75 | const amt = try file.readPositionalAll(io, strtab.items, pos); | |
| 76 | 76 | if (amt != obj_size) return error.InputOutput; |
| 77 | 77 | continue; |
| 78 | 78 | } |
src/link/Elf/AtomList.zig+8-4| ... | ... | @@ -90,7 +90,9 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void { |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | 92 | pub fn write(list: AtomList, buffer: *std.Io.Writer.Allocating, undefs: anytype, elf_file: *Elf) !void { |
| 93 | const gpa = elf_file.base.comp.gpa; | |
| 93 | const comp = elf_file.base.comp; | |
| 94 | const gpa = comp.gpa; | |
| 95 | const io = comp.io; | |
| 94 | 96 | const osec = elf_file.sections.items(.shdr)[list.output_section_index]; |
| 95 | 97 | assert(osec.sh_type != elf.SHT_NOBITS); |
| 96 | 98 | assert(!list.dirty); |
| ... | ... | @@ -121,12 +123,14 @@ pub fn write(list: AtomList, buffer: *std.Io.Writer.Allocating, undefs: anytype, |
| 121 | 123 | try atom_ptr.resolveRelocsAlloc(elf_file, out_code); |
| 122 | 124 | } |
| 123 | 125 | |
| 124 | try elf_file.base.file.?.pwriteAll(buffer.written(), list.offset(elf_file)); | |
| 126 | try elf_file.base.file.?.writePositionalAll(io, buffer.written(), list.offset(elf_file)); | |
| 125 | 127 | buffer.clearRetainingCapacity(); |
| 126 | 128 | } |
| 127 | 129 | |
| 128 | 130 | pub fn writeRelocatable(list: AtomList, buffer: *std.array_list.Managed(u8), elf_file: *Elf) !void { |
| 129 | const gpa = elf_file.base.comp.gpa; | |
| 131 | const comp = elf_file.base.comp; | |
| 132 | const gpa = comp.gpa; | |
| 133 | const io = comp.io; | |
| 130 | 134 | const osec = elf_file.sections.items(.shdr)[list.output_section_index]; |
| 131 | 135 | assert(osec.sh_type != elf.SHT_NOBITS); |
| 132 | 136 | |
| ... | ... | @@ -152,7 +156,7 @@ pub fn writeRelocatable(list: AtomList, buffer: *std.array_list.Managed(u8), elf |
| 152 | 156 | @memcpy(out_code, code); |
| 153 | 157 | } |
| 154 | 158 | |
| 155 | try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file)); | |
| 159 | try elf_file.base.file.?.writePositionalAll(io, buffer.items, list.offset(elf_file)); | |
| 156 | 160 | buffer.clearRetainingCapacity(); |
| 157 | 161 | } |
| 158 | 162 |
src/link/Elf/Object.zig+25-19| ... | ... | @@ -92,6 +92,7 @@ pub fn deinit(self: *Object, gpa: Allocator) void { |
| 92 | 92 | pub fn parse( |
| 93 | 93 | self: *Object, |
| 94 | 94 | gpa: Allocator, |
| 95 | io: Io, | |
| 95 | 96 | diags: *Diags, |
| 96 | 97 | /// For error reporting purposes only. |
| 97 | 98 | path: Path, |
| ... | ... | @@ -105,7 +106,7 @@ pub fn parse( |
| 105 | 106 | // Allocate atom index 0 to null atom |
| 106 | 107 | try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); |
| 107 | 108 | |
| 108 | try self.initAtoms(gpa, diags, path, handle, debug_fmt_strip, target); | |
| 109 | try self.initAtoms(gpa, io, diags, path, handle, debug_fmt_strip, target); | |
| 109 | 110 | try self.initSymbols(gpa, default_sym_version); |
| 110 | 111 | |
| 111 | 112 | for (self.shdrs.items, 0..) |shdr, i| { |
| ... | ... | @@ -114,7 +115,7 @@ pub fn parse( |
| 114 | 115 | if ((target.cpu.arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or |
| 115 | 116 | mem.eql(u8, self.getString(atom_ptr.name_offset), ".eh_frame")) |
| 116 | 117 | { |
| 117 | try self.parseEhFrame(gpa, handle, @intCast(i), target); | |
| 118 | try self.parseEhFrame(gpa, io, handle, @intCast(i), target); | |
| 118 | 119 | } |
| 119 | 120 | } |
| 120 | 121 | } |
| ... | ... | @@ -131,7 +132,7 @@ pub fn parseCommon( |
| 131 | 132 | const offset = if (self.archive) |ar| ar.offset else 0; |
| 132 | 133 | const file_size = (try handle.stat(io)).size; |
| 133 | 134 | |
| 134 | const header_buffer = try Elf.preadAllAlloc(gpa, handle, offset, @sizeOf(elf.Elf64_Ehdr)); | |
| 135 | const header_buffer = try Elf.preadAllAlloc(gpa, io, handle, offset, @sizeOf(elf.Elf64_Ehdr)); | |
| 135 | 136 | defer gpa.free(header_buffer); |
| 136 | 137 | self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*; |
| 137 | 138 | if (!mem.eql(u8, self.header.?.e_ident[0..4], elf.MAGIC)) { |
| ... | ... | @@ -155,7 +156,7 @@ pub fn parseCommon( |
| 155 | 156 | return diags.failParse(path, "corrupt header: section header table extends past the end of file", .{}); |
| 156 | 157 | } |
| 157 | 158 | |
| 158 | const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, offset + shoff, shsize); | |
| 159 | const shdrs_buffer = try Elf.preadAllAlloc(gpa, io, handle, offset + shoff, shsize); | |
| 159 | 160 | defer gpa.free(shdrs_buffer); |
| 160 | 161 | const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum]; |
| 161 | 162 | try self.shdrs.appendUnalignedSlice(gpa, shdrs); |
| ... | ... | @@ -168,7 +169,7 @@ pub fn parseCommon( |
| 168 | 169 | } |
| 169 | 170 | } |
| 170 | 171 | |
| 171 | const shstrtab = try self.preadShdrContentsAlloc(gpa, handle, self.header.?.e_shstrndx); | |
| 172 | const shstrtab = try self.preadShdrContentsAlloc(gpa, io, handle, self.header.?.e_shstrndx); | |
| 172 | 173 | defer gpa.free(shstrtab); |
| 173 | 174 | for (self.shdrs.items) |shdr| { |
| 174 | 175 | if (shdr.sh_name >= shstrtab.len) { |
| ... | ... | @@ -186,7 +187,7 @@ pub fn parseCommon( |
| 186 | 187 | const shdr = self.shdrs.items[index]; |
| 187 | 188 | self.first_global = shdr.sh_info; |
| 188 | 189 | |
| 189 | const raw_symtab = try self.preadShdrContentsAlloc(gpa, handle, index); | |
| 190 | const raw_symtab = try self.preadShdrContentsAlloc(gpa, io, handle, index); | |
| 190 | 191 | defer gpa.free(raw_symtab); |
| 191 | 192 | const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch { |
| 192 | 193 | return diags.failParse(path, "symbol table not evenly divisible", .{}); |
| ... | ... | @@ -194,7 +195,7 @@ pub fn parseCommon( |
| 194 | 195 | const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; |
| 195 | 196 | |
| 196 | 197 | const strtab_bias = @as(u32, @intCast(self.strtab.items.len)); |
| 197 | const strtab = try self.preadShdrContentsAlloc(gpa, handle, shdr.sh_link); | |
| 198 | const strtab = try self.preadShdrContentsAlloc(gpa, io, handle, shdr.sh_link); | |
| 198 | 199 | defer gpa.free(strtab); |
| 199 | 200 | try self.strtab.appendSlice(gpa, strtab); |
| 200 | 201 | |
| ... | ... | @@ -290,6 +291,7 @@ pub fn validateEFlags( |
| 290 | 291 | fn initAtoms( |
| 291 | 292 | self: *Object, |
| 292 | 293 | gpa: Allocator, |
| 294 | io: Io, | |
| 293 | 295 | diags: *Diags, |
| 294 | 296 | path: Path, |
| 295 | 297 | handle: Io.File, |
| ... | ... | @@ -325,7 +327,7 @@ fn initAtoms( |
| 325 | 327 | }; |
| 326 | 328 | |
| 327 | 329 | const shndx: u32 = @intCast(i); |
| 328 | const group_raw_data = try self.preadShdrContentsAlloc(gpa, handle, shndx); | |
| 330 | const group_raw_data = try self.preadShdrContentsAlloc(gpa, io, handle, shndx); | |
| 329 | 331 | defer gpa.free(group_raw_data); |
| 330 | 332 | const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch { |
| 331 | 333 | return diags.failParse(path, "corrupt section group: not evenly divisible ", .{}); |
| ... | ... | @@ -366,7 +368,7 @@ fn initAtoms( |
| 366 | 368 | const shndx: u32 = @intCast(i); |
| 367 | 369 | if (self.skipShdr(shndx, debug_fmt_strip)) continue; |
| 368 | 370 | const size, const alignment = if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) blk: { |
| 369 | const data = try self.preadShdrContentsAlloc(gpa, handle, shndx); | |
| 371 | const data = try self.preadShdrContentsAlloc(gpa, io, handle, shndx); | |
| 370 | 372 | defer gpa.free(data); |
| 371 | 373 | const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; |
| 372 | 374 | break :blk .{ chdr.ch_size, Alignment.fromNonzeroByteUnits(chdr.ch_addralign) }; |
| ... | ... | @@ -387,7 +389,7 @@ fn initAtoms( |
| 387 | 389 | elf.SHT_REL, elf.SHT_RELA => { |
| 388 | 390 | const atom_index = self.atoms_indexes.items[shdr.sh_info]; |
| 389 | 391 | if (self.atom(atom_index)) |atom_ptr| { |
| 390 | const relocs = try self.preadRelocsAlloc(gpa, handle, @intCast(i)); | |
| 392 | const relocs = try self.preadRelocsAlloc(gpa, io, handle, @intCast(i)); | |
| 391 | 393 | defer gpa.free(relocs); |
| 392 | 394 | atom_ptr.relocs_section_index = @intCast(i); |
| 393 | 395 | const rel_index: u32 = @intCast(self.relocs.items.len); |
| ... | ... | @@ -449,6 +451,7 @@ fn initSymbols( |
| 449 | 451 | fn parseEhFrame( |
| 450 | 452 | self: *Object, |
| 451 | 453 | gpa: Allocator, |
| 454 | io: Io, | |
| 452 | 455 | handle: Io.File, |
| 453 | 456 | shndx: u32, |
| 454 | 457 | target: *const std.Target, |
| ... | ... | @@ -458,12 +461,12 @@ fn parseEhFrame( |
| 458 | 461 | else => {}, |
| 459 | 462 | } else null; |
| 460 | 463 | |
| 461 | const raw = try self.preadShdrContentsAlloc(gpa, handle, shndx); | |
| 464 | const raw = try self.preadShdrContentsAlloc(gpa, io, handle, shndx); | |
| 462 | 465 | defer gpa.free(raw); |
| 463 | 466 | const data_start: u32 = @intCast(self.eh_frame_data.items.len); |
| 464 | 467 | try self.eh_frame_data.appendSlice(gpa, raw); |
| 465 | 468 | const relocs = if (relocs_shndx) |index| |
| 466 | try self.preadRelocsAlloc(gpa, handle, index) | |
| 469 | try self.preadRelocsAlloc(gpa, io, handle, index) | |
| 467 | 470 | else |
| 468 | 471 | &[0]elf.Elf64_Rela{}; |
| 469 | 472 | defer gpa.free(relocs); |
| ... | ... | @@ -1132,6 +1135,9 @@ pub fn updateArSize(self: *Object, elf_file: *Elf) !void { |
| 1132 | 1135 | } |
| 1133 | 1136 | |
| 1134 | 1137 | pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void { |
| 1138 | const comp = elf_file.base.comp; | |
| 1139 | const gpa = comp.gpa; | |
| 1140 | const io = comp.io; | |
| 1135 | 1141 | const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; |
| 1136 | 1142 | const offset: u64 = if (self.archive) |ar| ar.offset else 0; |
| 1137 | 1143 | const name = fs.path.basename(self.path.sub_path); |
| ... | ... | @@ -1144,10 +1150,9 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void { |
| 1144 | 1150 | }); |
| 1145 | 1151 | try writer.writeAll(mem.asBytes(&hdr)); |
| 1146 | 1152 | const handle = elf_file.fileHandle(self.file_handle); |
| 1147 | const gpa = elf_file.base.comp.gpa; | |
| 1148 | 1153 | const data = try gpa.alloc(u8, size); |
| 1149 | 1154 | defer gpa.free(data); |
| 1150 | const amt = try handle.preadAll(data, offset); | |
| 1155 | const amt = try handle.readPositionalAll(io, data, offset); | |
| 1151 | 1156 | if (amt != size) return error.InputOutput; |
| 1152 | 1157 | try writer.writeAll(data); |
| 1153 | 1158 | } |
| ... | ... | @@ -1220,11 +1225,12 @@ pub fn writeSymtab(self: *Object, elf_file: *Elf) void { |
| 1220 | 1225 | /// Caller owns the memory. |
| 1221 | 1226 | pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { |
| 1222 | 1227 | const comp = elf_file.base.comp; |
| 1228 | const io = comp.io; | |
| 1223 | 1229 | const gpa = comp.gpa; |
| 1224 | 1230 | const atom_ptr = self.atom(atom_index).?; |
| 1225 | 1231 | const shdr = atom_ptr.inputShdr(elf_file); |
| 1226 | 1232 | const handle = elf_file.fileHandle(self.file_handle); |
| 1227 | const data = try self.preadShdrContentsAlloc(gpa, handle, atom_ptr.input_section_index); | |
| 1233 | const data = try self.preadShdrContentsAlloc(gpa, io, handle, atom_ptr.input_section_index); | |
| 1228 | 1234 | defer if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) gpa.free(data); |
| 1229 | 1235 | |
| 1230 | 1236 | if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { |
| ... | ... | @@ -1340,18 +1346,18 @@ fn addString(self: *Object, gpa: Allocator, str: []const u8) !u32 { |
| 1340 | 1346 | } |
| 1341 | 1347 | |
| 1342 | 1348 | /// Caller owns the memory. |
| 1343 | fn preadShdrContentsAlloc(self: Object, gpa: Allocator, handle: Io.File, index: u32) ![]u8 { | |
| 1349 | fn preadShdrContentsAlloc(self: Object, gpa: Allocator, io: Io, handle: Io.File, index: u32) ![]u8 { | |
| 1344 | 1350 | assert(index < self.shdrs.items.len); |
| 1345 | 1351 | const offset = if (self.archive) |ar| ar.offset else 0; |
| 1346 | 1352 | const shdr = self.shdrs.items[index]; |
| 1347 | 1353 | const sh_offset = math.cast(u64, shdr.sh_offset) orelse return error.Overflow; |
| 1348 | 1354 | const sh_size = math.cast(u64, shdr.sh_size) orelse return error.Overflow; |
| 1349 | return Elf.preadAllAlloc(gpa, handle, offset + sh_offset, sh_size); | |
| 1355 | return Elf.preadAllAlloc(gpa, io, handle, offset + sh_offset, sh_size); | |
| 1350 | 1356 | } |
| 1351 | 1357 | |
| 1352 | 1358 | /// Caller owns the memory. |
| 1353 | fn preadRelocsAlloc(self: Object, gpa: Allocator, handle: Io.File, shndx: u32) ![]align(1) const elf.Elf64_Rela { | |
| 1354 | const raw = try self.preadShdrContentsAlloc(gpa, handle, shndx); | |
| 1359 | fn preadRelocsAlloc(self: Object, gpa: Allocator, io: Io, handle: Io.File, shndx: u32) ![]align(1) const elf.Elf64_Rela { | |
| 1360 | const raw = try self.preadShdrContentsAlloc(gpa, io, handle, shndx); | |
| 1355 | 1361 | const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela)); |
| 1356 | 1362 | return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num]; |
| 1357 | 1363 | } |
src/link/Elf/SharedObject.zig+11-9| ... | ... | @@ -109,16 +109,17 @@ pub const Parsed = struct { |
| 109 | 109 | |
| 110 | 110 | pub fn parseHeader( |
| 111 | 111 | gpa: Allocator, |
| 112 | io: Io, | |
| 112 | 113 | diags: *Diags, |
| 113 | 114 | file_path: Path, |
| 114 | fs_file: Io.File, | |
| 115 | file: Io.File, | |
| 115 | 116 | stat: Stat, |
| 116 | 117 | target: *const std.Target, |
| 117 | 118 | ) !Header { |
| 118 | 119 | var ehdr: elf.Elf64_Ehdr = undefined; |
| 119 | 120 | { |
| 120 | 121 | const buf = mem.asBytes(&ehdr); |
| 121 | const amt = try fs_file.preadAll(buf, 0); | |
| 122 | const amt = try file.readPositionalAll(io, buf, 0); | |
| 122 | 123 | if (amt != buf.len) return error.UnexpectedEndOfFile; |
| 123 | 124 | } |
| 124 | 125 | if (!mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")) return error.BadMagic; |
| ... | ... | @@ -135,7 +136,7 @@ pub fn parseHeader( |
| 135 | 136 | errdefer gpa.free(sections); |
| 136 | 137 | { |
| 137 | 138 | const buf = mem.sliceAsBytes(sections); |
| 138 | const amt = try fs_file.preadAll(buf, shoff); | |
| 139 | const amt = try file.readPositionalAll(io, buf, shoff); | |
| 139 | 140 | if (amt != buf.len) return error.UnexpectedEndOfFile; |
| 140 | 141 | } |
| 141 | 142 | |
| ... | ... | @@ -160,7 +161,7 @@ pub fn parseHeader( |
| 160 | 161 | const dynamic_table = try gpa.alloc(elf.Elf64_Dyn, n); |
| 161 | 162 | errdefer gpa.free(dynamic_table); |
| 162 | 163 | const buf = mem.sliceAsBytes(dynamic_table); |
| 163 | const amt = try fs_file.preadAll(buf, shdr.sh_offset); | |
| 164 | const amt = try file.readPositionalAll(io, buf, shdr.sh_offset); | |
| 164 | 165 | if (amt != buf.len) return error.UnexpectedEndOfFile; |
| 165 | 166 | break :dt dynamic_table; |
| 166 | 167 | } else &.{}; |
| ... | ... | @@ -175,7 +176,7 @@ pub fn parseHeader( |
| 175 | 176 | const strtab_shdr = sections[dynsym_shdr.sh_link]; |
| 176 | 177 | const n = std.math.cast(usize, strtab_shdr.sh_size) orelse return error.Overflow; |
| 177 | 178 | const buf = try strtab.addManyAsSlice(gpa, n); |
| 178 | const amt = try fs_file.preadAll(buf, strtab_shdr.sh_offset); | |
| 179 | const amt = try file.readPositionalAll(io, buf, strtab_shdr.sh_offset); | |
| 179 | 180 | if (amt != buf.len) return error.UnexpectedEndOfFile; |
| 180 | 181 | } |
| 181 | 182 | |
| ... | ... | @@ -207,9 +208,10 @@ pub fn parseHeader( |
| 207 | 208 | |
| 208 | 209 | pub fn parse( |
| 209 | 210 | gpa: Allocator, |
| 211 | io: Io, | |
| 210 | 212 | /// Moves resources from header. Caller may unconditionally deinit. |
| 211 | 213 | header: *Header, |
| 212 | fs_file: Io.File, | |
| 214 | file: Io.File, | |
| 213 | 215 | ) !Parsed { |
| 214 | 216 | const symtab = if (header.dynsym_sect_index) |index| st: { |
| 215 | 217 | const shdr = header.sections[index]; |
| ... | ... | @@ -217,7 +219,7 @@ pub fn parse( |
| 217 | 219 | const symtab = try gpa.alloc(elf.Elf64_Sym, n); |
| 218 | 220 | errdefer gpa.free(symtab); |
| 219 | 221 | const buf = mem.sliceAsBytes(symtab); |
| 220 | const amt = try fs_file.preadAll(buf, shdr.sh_offset); | |
| 222 | const amt = try file.readPositionalAll(io, buf, shdr.sh_offset); | |
| 221 | 223 | if (amt != buf.len) return error.UnexpectedEndOfFile; |
| 222 | 224 | break :st symtab; |
| 223 | 225 | } else &.{}; |
| ... | ... | @@ -228,7 +230,7 @@ pub fn parse( |
| 228 | 230 | |
| 229 | 231 | if (header.verdef_sect_index) |shndx| { |
| 230 | 232 | const shdr = header.sections[shndx]; |
| 231 | const verdefs = try Elf.preadAllAlloc(gpa, fs_file, shdr.sh_offset, shdr.sh_size); | |
| 233 | const verdefs = try Elf.preadAllAlloc(gpa, io, file, shdr.sh_offset, shdr.sh_size); | |
| 232 | 234 | defer gpa.free(verdefs); |
| 233 | 235 | |
| 234 | 236 | var offset: u32 = 0; |
| ... | ... | @@ -254,7 +256,7 @@ pub fn parse( |
| 254 | 256 | const versyms = try gpa.alloc(elf.Versym, symtab.len); |
| 255 | 257 | errdefer gpa.free(versyms); |
| 256 | 258 | const buf = mem.sliceAsBytes(versyms); |
| 257 | const amt = try fs_file.preadAll(buf, shdr.sh_offset); | |
| 259 | const amt = try file.readPositionalAll(io, buf, shdr.sh_offset); | |
| 258 | 260 | if (amt != buf.len) return error.UnexpectedEndOfFile; |
| 259 | 261 | break :vs versyms; |
| 260 | 262 | } else &.{}; |
src/link/Elf/ZigObject.zig+19-9| ... | ... | @@ -740,7 +740,9 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O |
| 740 | 740 | /// We need this so that we can write to an archive. |
| 741 | 741 | /// TODO implement writing ZigObject data directly to a buffer instead. |
| 742 | 742 | pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void { |
| 743 | const gpa = elf_file.base.comp.gpa; | |
| 743 | const comp = elf_file.base.comp; | |
| 744 | const gpa = comp.gpa; | |
| 745 | const io = comp.io; | |
| 744 | 746 | const shsize: u64 = switch (elf_file.ptr_width) { |
| 745 | 747 | .p32 => @sizeOf(elf.Elf32_Shdr), |
| 746 | 748 | .p64 => @sizeOf(elf.Elf64_Shdr), |
| ... | ... | @@ -753,7 +755,7 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void { |
| 753 | 755 | const size = std.math.cast(usize, end_pos) orelse return error.Overflow; |
| 754 | 756 | try self.data.resize(gpa, size); |
| 755 | 757 | |
| 756 | const amt = try elf_file.base.file.?.preadAll(self.data.items, 0); | |
| 758 | const amt = try elf_file.base.file.?.readPositionalAll(io, self.data.items, 0); | |
| 757 | 759 | if (amt != size) return error.InputOutput; |
| 758 | 760 | } |
| 759 | 761 | |
| ... | ... | @@ -901,13 +903,15 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void { |
| 901 | 903 | /// Returns atom's code. |
| 902 | 904 | /// Caller owns the memory. |
| 903 | 905 | pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { |
| 904 | const gpa = elf_file.base.comp.gpa; | |
| 906 | const comp = elf_file.base.comp; | |
| 907 | const gpa = comp.gpa; | |
| 908 | const io = comp.io; | |
| 905 | 909 | const atom_ptr = self.atom(atom_index).?; |
| 906 | 910 | const file_offset = atom_ptr.offset(elf_file); |
| 907 | 911 | const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| 908 | 912 | const code = try gpa.alloc(u8, size); |
| 909 | 913 | errdefer gpa.free(code); |
| 910 | const amt = try elf_file.base.file.?.preadAll(code, file_offset); | |
| 914 | const amt = try elf_file.base.file.?.readPositionalAll(io, code, file_offset); | |
| 911 | 915 | if (amt != code.len) { |
| 912 | 916 | log.err("fetching code for {s} failed", .{atom_ptr.name(elf_file)}); |
| 913 | 917 | return error.InputOutput; |
| ... | ... | @@ -1365,6 +1369,8 @@ fn updateNavCode( |
| 1365 | 1369 | ) link.File.UpdateNavError!void { |
| 1366 | 1370 | const zcu = pt.zcu; |
| 1367 | 1371 | const gpa = zcu.gpa; |
| 1372 | const comp = elf_file.base.comp; | |
| 1373 | const io = comp.io; | |
| 1368 | 1374 | const ip = &zcu.intern_pool; |
| 1369 | 1375 | const nav = ip.getNav(nav_index); |
| 1370 | 1376 | |
| ... | ... | @@ -1449,8 +1455,8 @@ fn updateNavCode( |
| 1449 | 1455 | const shdr = elf_file.sections.items(.shdr)[shdr_index]; |
| 1450 | 1456 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 1451 | 1457 | const file_offset = atom_ptr.offset(elf_file); |
| 1452 | elf_file.base.file.?.pwriteAll(code, file_offset) catch |err| | |
| 1453 | return elf_file.base.cgFail(nav_index, "failed to write to output file: {s}", .{@errorName(err)}); | |
| 1458 | elf_file.base.file.?.writePositionalAll(io, code, file_offset) catch |err| | |
| 1459 | return elf_file.base.cgFail(nav_index, "failed to write to output file: {t}", .{err}); | |
| 1454 | 1460 | log.debug("writing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len }); |
| 1455 | 1461 | } |
| 1456 | 1462 | } |
| ... | ... | @@ -1467,6 +1473,8 @@ fn updateTlv( |
| 1467 | 1473 | const zcu = pt.zcu; |
| 1468 | 1474 | const ip = &zcu.intern_pool; |
| 1469 | 1475 | const gpa = zcu.gpa; |
| 1476 | const comp = elf_file.base.comp; | |
| 1477 | const io = comp.io; | |
| 1470 | 1478 | const nav = ip.getNav(nav_index); |
| 1471 | 1479 | |
| 1472 | 1480 | log.debug("updateTlv {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); |
| ... | ... | @@ -1503,8 +1511,8 @@ fn updateTlv( |
| 1503 | 1511 | const shdr = elf_file.sections.items(.shdr)[shndx]; |
| 1504 | 1512 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 1505 | 1513 | const file_offset = atom_ptr.offset(elf_file); |
| 1506 | elf_file.base.file.?.pwriteAll(code, file_offset) catch |err| | |
| 1507 | return elf_file.base.cgFail(nav_index, "failed to write to output file: {s}", .{@errorName(err)}); | |
| 1514 | elf_file.base.file.?.writePositionalAll(io, code, file_offset) catch |err| | |
| 1515 | return elf_file.base.cgFail(nav_index, "failed to write to output file: {t}", .{err}); | |
| 1508 | 1516 | log.debug("writing TLV {s} from 0x{x} to 0x{x}", .{ |
| 1509 | 1517 | atom_ptr.name(elf_file), |
| 1510 | 1518 | file_offset, |
| ... | ... | @@ -2003,6 +2011,8 @@ fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 { |
| 2003 | 2011 | } |
| 2004 | 2012 | |
| 2005 | 2013 | fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void { |
| 2014 | const comp = elf_file.base.comp; | |
| 2015 | const io = comp.io; | |
| 2006 | 2016 | const atom_ptr = tr_sym.atom(elf_file).?; |
| 2007 | 2017 | const fileoff = atom_ptr.offset(elf_file); |
| 2008 | 2018 | const source_addr = tr_sym.address(.{}, elf_file); |
| ... | ... | @@ -2012,7 +2022,7 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void { |
| 2012 | 2022 | .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf), |
| 2013 | 2023 | else => @panic("TODO implement write trampoline for this CPU arch"), |
| 2014 | 2024 | }; |
| 2015 | try elf_file.base.file.?.pwriteAll(out, fileoff); | |
| 2025 | try elf_file.base.file.?.writePositionalAll(io, out, fileoff); | |
| 2016 | 2026 | |
| 2017 | 2027 | if (elf_file.base.child_pid) |pid| { |
| 2018 | 2028 | switch (builtin.os.tag) { |
src/link/Elf/relocatable.zig+32-33| ... | ... | @@ -1,3 +1,23 @@ |
| 1 | const std = @import("std"); | |
| 2 | const assert = std.debug.assert; | |
| 3 | const elf = std.elf; | |
| 4 | const math = std.math; | |
| 5 | const mem = std.mem; | |
| 6 | const Path = std.Build.Cache.Path; | |
| 7 | const log = std.log.scoped(.link); | |
| 8 | const state_log = std.log.scoped(.link_state); | |
| 9 | ||
| 10 | const build_options = @import("build_options"); | |
| 11 | ||
| 12 | const eh_frame = @import("eh_frame.zig"); | |
| 13 | const link = @import("../../link.zig"); | |
| 14 | const Archive = @import("Archive.zig"); | |
| 15 | const Compilation = @import("../../Compilation.zig"); | |
| 16 | const Elf = @import("../Elf.zig"); | |
| 17 | const File = @import("file.zig").File; | |
| 18 | const Object = @import("Object.zig"); | |
| 19 | const Symbol = @import("Symbol.zig"); | |
| 20 | ||
| 1 | 21 | pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void { |
| 2 | 22 | const gpa = comp.gpa; |
| 3 | 23 | const io = comp.io; |
| ... | ... | @@ -127,7 +147,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void { |
| 127 | 147 | assert(writer.buffered().len == total_size); |
| 128 | 148 | |
| 129 | 149 | try elf_file.base.file.?.setLength(io, total_size); |
| 130 | try elf_file.base.file.?.pwriteAll(writer.buffered(), 0); | |
| 150 | try elf_file.base.file.?.writePositionalAll(io, writer.buffered(), 0); | |
| 131 | 151 | |
| 132 | 152 | if (diags.hasErrors()) return error.LinkFailure; |
| 133 | 153 | } |
| ... | ... | @@ -331,13 +351,7 @@ fn allocateAllocSections(elf_file: *Elf) !void { |
| 331 | 351 | |
| 332 | 352 | if (shdr.sh_offset > 0) { |
| 333 | 353 | const existing_size = elf_file.sectionSize(@intCast(shndx)); |
| 334 | const amt = try elf_file.base.file.?.copyRangeAll( | |
| 335 | shdr.sh_offset, | |
| 336 | elf_file.base.file.?, | |
| 337 | new_offset, | |
| 338 | existing_size, | |
| 339 | ); | |
| 340 | if (amt != existing_size) return error.InputOutput; | |
| 354 | try elf_file.base.copyRangeAll(shdr.sh_offset, new_offset, existing_size); | |
| 341 | 355 | } |
| 342 | 356 | |
| 343 | 357 | shdr.sh_offset = new_offset; |
| ... | ... | @@ -361,7 +375,9 @@ fn writeAtoms(elf_file: *Elf) !void { |
| 361 | 375 | } |
| 362 | 376 | |
| 363 | 377 | fn writeSyntheticSections(elf_file: *Elf) !void { |
| 364 | const gpa = elf_file.base.comp.gpa; | |
| 378 | const comp = elf_file.base.comp; | |
| 379 | const io = comp.io; | |
| 380 | const gpa = comp.gpa; | |
| 365 | 381 | const slice = elf_file.sections.slice(); |
| 366 | 382 | |
| 367 | 383 | const SortRelocs = struct { |
| ... | ... | @@ -398,7 +414,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void { |
| 398 | 414 | shdr.sh_offset + shdr.sh_size, |
| 399 | 415 | }); |
| 400 | 416 | |
| 401 | try elf_file.base.file.?.pwriteAll(@ptrCast(relocs.items), shdr.sh_offset); | |
| 417 | try elf_file.base.file.?.writePositionalAll(io, @ptrCast(relocs.items), shdr.sh_offset); | |
| 402 | 418 | } |
| 403 | 419 | |
| 404 | 420 | if (elf_file.section_indexes.eh_frame) |shndx| { |
| ... | ... | @@ -418,7 +434,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void { |
| 418 | 434 | shdr.sh_offset + sh_size, |
| 419 | 435 | }); |
| 420 | 436 | assert(writer.buffered().len == sh_size - existing_size); |
| 421 | try elf_file.base.file.?.pwriteAll(writer.buffered(), shdr.sh_offset + existing_size); | |
| 437 | try elf_file.base.file.?.writePositionalAll(io, writer.buffered(), shdr.sh_offset + existing_size); | |
| 422 | 438 | } |
| 423 | 439 | if (elf_file.section_indexes.eh_frame_rela) |shndx| { |
| 424 | 440 | const shdr = slice.items(.shdr)[shndx]; |
| ... | ... | @@ -436,7 +452,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void { |
| 436 | 452 | shdr.sh_offset, |
| 437 | 453 | shdr.sh_offset + shdr.sh_size, |
| 438 | 454 | }); |
| 439 | try elf_file.base.file.?.pwriteAll(@ptrCast(relocs.items), shdr.sh_offset); | |
| 455 | try elf_file.base.file.?.writePositionalAll(io, @ptrCast(relocs.items), shdr.sh_offset); | |
| 440 | 456 | } |
| 441 | 457 | |
| 442 | 458 | try writeGroups(elf_file); |
| ... | ... | @@ -445,7 +461,9 @@ fn writeSyntheticSections(elf_file: *Elf) !void { |
| 445 | 461 | } |
| 446 | 462 | |
| 447 | 463 | fn writeGroups(elf_file: *Elf) !void { |
| 448 | const gpa = elf_file.base.comp.gpa; | |
| 464 | const comp = elf_file.base.comp; | |
| 465 | const io = comp.io; | |
| 466 | const gpa = comp.gpa; | |
| 449 | 467 | for (elf_file.group_sections.items) |cgs| { |
| 450 | 468 | const shdr = elf_file.sections.items(.shdr)[cgs.shndx]; |
| 451 | 469 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; |
| ... | ... | @@ -458,25 +476,6 @@ fn writeGroups(elf_file: *Elf) !void { |
| 458 | 476 | shdr.sh_offset, |
| 459 | 477 | shdr.sh_offset + shdr.sh_size, |
| 460 | 478 | }); |
| 461 | try elf_file.base.file.?.pwriteAll(writer.buffered(), shdr.sh_offset); | |
| 479 | try elf_file.base.file.?.writePositionalAll(io, writer.buffered(), shdr.sh_offset); | |
| 462 | 480 | } |
| 463 | 481 | } |
| 464 | ||
| 465 | const assert = std.debug.assert; | |
| 466 | const build_options = @import("build_options"); | |
| 467 | const eh_frame = @import("eh_frame.zig"); | |
| 468 | const elf = std.elf; | |
| 469 | const link = @import("../../link.zig"); | |
| 470 | const log = std.log.scoped(.link); | |
| 471 | const math = std.math; | |
| 472 | const mem = std.mem; | |
| 473 | const state_log = std.log.scoped(.link_state); | |
| 474 | const Path = std.Build.Cache.Path; | |
| 475 | const std = @import("std"); | |
| 476 | ||
| 477 | const Archive = @import("Archive.zig"); | |
| 478 | const Compilation = @import("../../Compilation.zig"); | |
| 479 | const Elf = @import("../Elf.zig"); | |
| 480 | const File = @import("file.zig").File; | |
| 481 | const Object = @import("Object.zig"); | |
| 482 | const Symbol = @import("Symbol.zig"); |
src/link/Lld.zig+14-8| ... | ... | @@ -406,6 +406,7 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { |
| 406 | 406 | the_object_path.sub_path, |
| 407 | 407 | directory.handle, |
| 408 | 408 | base.emit.sub_path, |
| 409 | io, | |
| 409 | 410 | .{}, |
| 410 | 411 | ); |
| 411 | 412 | } else { |
| ... | ... | @@ -756,6 +757,7 @@ fn findLib(arena: Allocator, io: Io, name: []const u8, lib_directories: []const |
| 756 | 757 | fn elfLink(lld: *Lld, arena: Allocator) !void { |
| 757 | 758 | const comp = lld.base.comp; |
| 758 | 759 | const gpa = comp.gpa; |
| 760 | const io = comp.io; | |
| 759 | 761 | const diags = &comp.link_diags; |
| 760 | 762 | const base = &lld.base; |
| 761 | 763 | const elf = &lld.ofmt.elf; |
| ... | ... | @@ -822,6 +824,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { |
| 822 | 824 | the_object_path.sub_path, |
| 823 | 825 | directory.handle, |
| 824 | 826 | base.emit.sub_path, |
| 827 | io, | |
| 825 | 828 | .{}, |
| 826 | 829 | ); |
| 827 | 830 | } else { |
| ... | ... | @@ -1336,6 +1339,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { |
| 1336 | 1339 | const wasm = &lld.ofmt.wasm; |
| 1337 | 1340 | |
| 1338 | 1341 | const gpa = comp.gpa; |
| 1342 | const io = comp.io; | |
| 1339 | 1343 | |
| 1340 | 1344 | const directory = base.emit.root_dir; // Just an alias to make it shorter to type. |
| 1341 | 1345 | const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); |
| ... | ... | @@ -1378,6 +1382,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { |
| 1378 | 1382 | the_object_path.sub_path, |
| 1379 | 1383 | directory.handle, |
| 1380 | 1384 | base.emit.sub_path, |
| 1385 | io, | |
| 1381 | 1386 | .{}, |
| 1382 | 1387 | ); |
| 1383 | 1388 | } else { |
| ... | ... | @@ -1571,7 +1576,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { |
| 1571 | 1576 | comp.config.output_mode == .Exe) |
| 1572 | 1577 | { |
| 1573 | 1578 | // chmod does not interact with umask, so we use a conservative -rwxr--r-- here. |
| 1574 | Io.Dir.cwd().setFilePermissions(full_out_path, .fromMode(0o744), .{}) catch |err| | |
| 1579 | Io.Dir.cwd().setFilePermissions(io, full_out_path, .fromMode(0o744), .{}) catch |err| | |
| 1575 | 1580 | return diags.fail("{s}: failed to enable executable permissions: {t}", .{ full_out_path, err }); |
| 1576 | 1581 | } |
| 1577 | 1582 | } |
| ... | ... | @@ -1579,6 +1584,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { |
| 1579 | 1584 | |
| 1580 | 1585 | fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !void { |
| 1581 | 1586 | const io = comp.io; |
| 1587 | const gpa = comp.gpa; | |
| 1582 | 1588 | |
| 1583 | 1589 | if (comp.verbose_link) { |
| 1584 | 1590 | // Skip over our own name so that the LLD linker name is the first argv item. |
| ... | ... | @@ -1596,7 +1602,7 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi |
| 1596 | 1602 | } |
| 1597 | 1603 | |
| 1598 | 1604 | var stderr: []u8 = &.{}; |
| 1599 | defer comp.gpa.free(stderr); | |
| 1605 | defer gpa.free(stderr); | |
| 1600 | 1606 | |
| 1601 | 1607 | var child = std.process.Child.init(argv, arena); |
| 1602 | 1608 | const term = (if (comp.clang_passthrough_mode) term: { |
| ... | ... | @@ -1612,8 +1618,8 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi |
| 1612 | 1618 | |
| 1613 | 1619 | child.spawn(io) catch |err| break :term err; |
| 1614 | 1620 | var stderr_reader = child.stderr.?.readerStreaming(io, &.{}); |
| 1615 | stderr = try stderr_reader.interface.allocRemaining(comp.gpa, .unlimited); | |
| 1616 | break :term child.wait(); | |
| 1621 | stderr = try stderr_reader.interface.allocRemaining(gpa, .unlimited); | |
| 1622 | break :term child.wait(io); | |
| 1617 | 1623 | }) catch |first_err| term: { |
| 1618 | 1624 | const err = switch (first_err) { |
| 1619 | 1625 | error.NameTooLong => err: { |
| ... | ... | @@ -1622,8 +1628,8 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi |
| 1622 | 1628 | const rsp_path = "tmp" ++ s ++ std.fmt.hex(rand_int) ++ ".rsp"; |
| 1623 | 1629 | |
| 1624 | 1630 | const rsp_file = try comp.dirs.local_cache.handle.createFile(io, rsp_path, .{}); |
| 1625 | defer comp.dirs.local_cache.handle.deleteFileZ(rsp_path) catch |err| | |
| 1626 | log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) }); | |
| 1631 | defer comp.dirs.local_cache.handle.deleteFile(io, rsp_path) catch |err| | |
| 1632 | log.warn("failed to delete response file {s}: {t}", .{ rsp_path, err }); | |
| 1627 | 1633 | { |
| 1628 | 1634 | defer rsp_file.close(io); |
| 1629 | 1635 | var rsp_file_buffer: [1024]u8 = undefined; |
| ... | ... | @@ -1662,8 +1668,8 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi |
| 1662 | 1668 | |
| 1663 | 1669 | rsp_child.spawn(io) catch |err| break :err err; |
| 1664 | 1670 | var stderr_reader = rsp_child.stderr.?.readerStreaming(io, &.{}); |
| 1665 | stderr = try stderr_reader.interface.allocRemaining(comp.gpa, .unlimited); | |
| 1666 | break :term rsp_child.wait() catch |err| break :err err; | |
| 1671 | stderr = try stderr_reader.interface.allocRemaining(gpa, .unlimited); | |
| 1672 | break :term rsp_child.wait(io) catch |err| break :err err; | |
| 1667 | 1673 | } |
| 1668 | 1674 | }, |
| 1669 | 1675 | else => first_err, |
src/link/MachO.zig+64-41| ... | ... | @@ -347,7 +347,8 @@ pub fn flush( |
| 347 | 347 | |
| 348 | 348 | const comp = self.base.comp; |
| 349 | 349 | const gpa = comp.gpa; |
| 350 | const diags = &self.base.comp.link_diags; | |
| 350 | const io = comp.io; | |
| 351 | const diags = &comp.link_diags; | |
| 351 | 352 | |
| 352 | 353 | const sub_prog_node = prog_node.start("MachO Flush", 0); |
| 353 | 354 | defer sub_prog_node.end(); |
| ... | ... | @@ -380,26 +381,26 @@ pub fn flush( |
| 380 | 381 | // in this set. |
| 381 | 382 | try positionals.ensureUnusedCapacity(comp.c_object_table.keys().len); |
| 382 | 383 | for (comp.c_object_table.keys()) |key| { |
| 383 | positionals.appendAssumeCapacity(try link.openObjectInput(diags, key.status.success.object_path)); | |
| 384 | positionals.appendAssumeCapacity(try link.openObjectInput(io, diags, key.status.success.object_path)); | |
| 384 | 385 | } |
| 385 | 386 | |
| 386 | if (zcu_obj_path) |path| try positionals.append(try link.openObjectInput(diags, path)); | |
| 387 | if (zcu_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path)); | |
| 387 | 388 | |
| 388 | 389 | if (comp.config.any_sanitize_thread) { |
| 389 | try positionals.append(try link.openObjectInput(diags, comp.tsan_lib.?.full_object_path)); | |
| 390 | try positionals.append(try link.openObjectInput(io, diags, comp.tsan_lib.?.full_object_path)); | |
| 390 | 391 | } |
| 391 | 392 | |
| 392 | 393 | if (comp.config.any_fuzz) { |
| 393 | try positionals.append(try link.openArchiveInput(diags, comp.fuzzer_lib.?.full_object_path, false, false)); | |
| 394 | try positionals.append(try link.openArchiveInput(io, diags, comp.fuzzer_lib.?.full_object_path, false, false)); | |
| 394 | 395 | } |
| 395 | 396 | |
| 396 | 397 | if (comp.ubsan_rt_lib) |crt_file| { |
| 397 | 398 | const path = crt_file.full_object_path; |
| 398 | self.classifyInputFile(try link.openArchiveInput(diags, path, false, false)) catch |err| | |
| 399 | self.classifyInputFile(try link.openArchiveInput(io, diags, path, false, false)) catch |err| | |
| 399 | 400 | diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)}); |
| 400 | 401 | } else if (comp.ubsan_rt_obj) |crt_file| { |
| 401 | 402 | const path = crt_file.full_object_path; |
| 402 | self.classifyInputFile(try link.openObjectInput(diags, path)) catch |err| | |
| 403 | self.classifyInputFile(try link.openObjectInput(io, diags, path)) catch |err| | |
| 403 | 404 | diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)}); |
| 404 | 405 | } |
| 405 | 406 | |
| ... | ... | @@ -434,7 +435,7 @@ pub fn flush( |
| 434 | 435 | if (comp.config.link_libc and is_exe_or_dyn_lib) { |
| 435 | 436 | if (comp.zigc_static_lib) |zigc| { |
| 436 | 437 | const path = zigc.full_object_path; |
| 437 | self.classifyInputFile(try link.openArchiveInput(diags, path, false, false)) catch |err| | |
| 438 | self.classifyInputFile(try link.openArchiveInput(io, diags, path, false, false)) catch |err| | |
| 438 | 439 | diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)}); |
| 439 | 440 | } |
| 440 | 441 | } |
| ... | ... | @@ -457,12 +458,12 @@ pub fn flush( |
| 457 | 458 | for (system_libs.items) |lib| { |
| 458 | 459 | switch (Compilation.classifyFileExt(lib.path.sub_path)) { |
| 459 | 460 | .shared_library => { |
| 460 | const dso_input = try link.openDsoInput(diags, lib.path, lib.needed, lib.weak, lib.reexport); | |
| 461 | const dso_input = try link.openDsoInput(io, diags, lib.path, lib.needed, lib.weak, lib.reexport); | |
| 461 | 462 | self.classifyInputFile(dso_input) catch |err| |
| 462 | 463 | diags.addParseError(lib.path, "failed to parse input file: {s}", .{@errorName(err)}); |
| 463 | 464 | }, |
| 464 | 465 | .static_library => { |
| 465 | const archive_input = try link.openArchiveInput(diags, lib.path, lib.must_link, lib.hidden); | |
| 466 | const archive_input = try link.openArchiveInput(io, diags, lib.path, lib.must_link, lib.hidden); | |
| 466 | 467 | self.classifyInputFile(archive_input) catch |err| |
| 467 | 468 | diags.addParseError(lib.path, "failed to parse input file: {s}", .{@errorName(err)}); |
| 468 | 469 | }, |
| ... | ... | @@ -473,11 +474,11 @@ pub fn flush( |
| 473 | 474 | // Finally, link against compiler_rt. |
| 474 | 475 | if (comp.compiler_rt_lib) |crt_file| { |
| 475 | 476 | const path = crt_file.full_object_path; |
| 476 | self.classifyInputFile(try link.openArchiveInput(diags, path, false, false)) catch |err| | |
| 477 | self.classifyInputFile(try link.openArchiveInput(io, diags, path, false, false)) catch |err| | |
| 477 | 478 | diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)}); |
| 478 | 479 | } else if (comp.compiler_rt_obj) |crt_file| { |
| 479 | 480 | const path = crt_file.full_object_path; |
| 480 | self.classifyInputFile(try link.openObjectInput(diags, path)) catch |err| | |
| 481 | self.classifyInputFile(try link.openObjectInput(io, diags, path)) catch |err| | |
| 481 | 482 | diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)}); |
| 482 | 483 | } |
| 483 | 484 | |
| ... | ... | @@ -568,7 +569,7 @@ pub fn flush( |
| 568 | 569 | self.writeLinkeditSectionsToFile() catch |err| switch (err) { |
| 569 | 570 | error.OutOfMemory => return error.OutOfMemory, |
| 570 | 571 | error.LinkFailure => return error.LinkFailure, |
| 571 | else => |e| return diags.fail("failed to write linkedit sections to file: {s}", .{@errorName(e)}), | |
| 572 | else => |e| return diags.fail("failed to write linkedit sections to file: {t}", .{e}), | |
| 572 | 573 | }; |
| 573 | 574 | |
| 574 | 575 | var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: { |
| ... | ... | @@ -579,8 +580,8 @@ pub fn flush( |
| 579 | 580 | // where the code signature goes into. |
| 580 | 581 | var codesig = CodeSignature.init(self.getPageSize()); |
| 581 | 582 | codesig.code_directory.ident = fs.path.basename(self.base.emit.sub_path); |
| 582 | if (self.entitlements) |path| codesig.addEntitlements(gpa, path) catch |err| | |
| 583 | return diags.fail("failed to add entitlements from {s}: {s}", .{ path, @errorName(err) }); | |
| 583 | if (self.entitlements) |path| codesig.addEntitlements(gpa, io, path) catch |err| | |
| 584 | return diags.fail("failed to add entitlements from {s}: {t}", .{ path, err }); | |
| 584 | 585 | try self.writeCodeSignaturePadding(&codesig); |
| 585 | 586 | break :blk codesig; |
| 586 | 587 | } else null; |
| ... | ... | @@ -866,6 +867,9 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void { |
| 866 | 867 | const tracy = trace(@src()); |
| 867 | 868 | defer tracy.end(); |
| 868 | 869 | |
| 870 | const comp = self.base.comp; | |
| 871 | const io = comp.io; | |
| 872 | ||
| 869 | 873 | const path, const file = input.pathAndFile().?; |
| 870 | 874 | // TODO don't classify now, it's too late. The input file has already been classified |
| 871 | 875 | log.debug("classifying input file {f}", .{path}); |
| ... | ... | @@ -876,7 +880,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void { |
| 876 | 880 | const fat_arch: ?fat.Arch = try self.parseFatFile(file, path); |
| 877 | 881 | const offset = if (fat_arch) |fa| fa.offset else 0; |
| 878 | 882 | |
| 879 | if (readMachHeader(file, offset) catch null) |h| blk: { | |
| 883 | if (readMachHeader(io, file, offset) catch null) |h| blk: { | |
| 880 | 884 | if (h.magic != macho.MH_MAGIC_64) break :blk; |
| 881 | 885 | switch (h.filetype) { |
| 882 | 886 | macho.MH_OBJECT => try self.addObject(path, fh, offset), |
| ... | ... | @@ -885,7 +889,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void { |
| 885 | 889 | } |
| 886 | 890 | return; |
| 887 | 891 | } |
| 888 | if (readArMagic(file, offset, &buffer) catch null) |ar_magic| blk: { | |
| 892 | if (readArMagic(io, file, offset, &buffer) catch null) |ar_magic| blk: { | |
| 889 | 893 | if (!mem.eql(u8, ar_magic, Archive.ARMAG)) break :blk; |
| 890 | 894 | try self.addArchive(input.archive, fh, fat_arch); |
| 891 | 895 | return; |
| ... | ... | @@ -894,11 +898,13 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void { |
| 894 | 898 | } |
| 895 | 899 | |
| 896 | 900 | fn parseFatFile(self: *MachO, file: Io.File, path: Path) !?fat.Arch { |
| 897 | const diags = &self.base.comp.link_diags; | |
| 898 | const fat_h = fat.readFatHeader(file) catch return null; | |
| 901 | const comp = self.base.comp; | |
| 902 | const io = comp.io; | |
| 903 | const diags = &comp.link_diags; | |
| 904 | const fat_h = fat.readFatHeader(io, file) catch return null; | |
| 899 | 905 | if (fat_h.magic != macho.FAT_MAGIC and fat_h.magic != macho.FAT_MAGIC_64) return null; |
| 900 | 906 | var fat_archs_buffer: [2]fat.Arch = undefined; |
| 901 | const fat_archs = try fat.parseArchs(file, fat_h, &fat_archs_buffer); | |
| 907 | const fat_archs = try fat.parseArchs(io, file, fat_h, &fat_archs_buffer); | |
| 902 | 908 | const cpu_arch = self.getTarget().cpu.arch; |
| 903 | 909 | for (fat_archs) |arch| { |
| 904 | 910 | if (arch.tag == cpu_arch) return arch; |
| ... | ... | @@ -906,16 +912,16 @@ fn parseFatFile(self: *MachO, file: Io.File, path: Path) !?fat.Arch { |
| 906 | 912 | return diags.failParse(path, "missing arch in universal file: expected {s}", .{@tagName(cpu_arch)}); |
| 907 | 913 | } |
| 908 | 914 | |
| 909 | pub fn readMachHeader(file: Io.File, offset: usize) !macho.mach_header_64 { | |
| 915 | pub fn readMachHeader(io: Io, file: Io.File, offset: usize) !macho.mach_header_64 { | |
| 910 | 916 | var buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; |
| 911 | const nread = try file.preadAll(&buffer, offset); | |
| 917 | const nread = try file.readPositionalAll(io, &buffer, offset); | |
| 912 | 918 | if (nread != buffer.len) return error.InputOutput; |
| 913 | 919 | const hdr = @as(*align(1) const macho.mach_header_64, @ptrCast(&buffer)).*; |
| 914 | 920 | return hdr; |
| 915 | 921 | } |
| 916 | 922 | |
| 917 | pub fn readArMagic(file: Io.File, offset: usize, buffer: *[Archive.SARMAG]u8) ![]const u8 { | |
| 918 | const nread = try file.preadAll(buffer, offset); | |
| 923 | pub fn readArMagic(io: Io, file: Io.File, offset: usize, buffer: *[Archive.SARMAG]u8) ![]const u8 { | |
| 924 | const nread = try file.readPositionalAll(io, buffer, offset); | |
| 919 | 925 | if (nread != buffer.len) return error.InputOutput; |
| 920 | 926 | return buffer[0..Archive.SARMAG]; |
| 921 | 927 | } |
| ... | ... | @@ -1212,7 +1218,8 @@ fn parseDependentDylibs(self: *MachO) !void { |
| 1212 | 1218 | const rel_path = try fs.path.join(arena, &.{ prefix, path }); |
| 1213 | 1219 | try checked_paths.append(rel_path); |
| 1214 | 1220 | var buffer: [fs.max_path_bytes]u8 = undefined; |
| 1215 | const full_path = fs.realpath(rel_path, &buffer) catch continue; | |
| 1221 | // TODO don't use realpath | |
| 1222 | const full_path = buffer[0 .. Io.Dir.realPathAbsolute(io, rel_path, &buffer) catch continue]; | |
| 1216 | 1223 | break :full_path try arena.dupe(u8, full_path); |
| 1217 | 1224 | } |
| 1218 | 1225 | } else if (eatPrefix(id.name, "@loader_path/")) |_| { |
| ... | ... | @@ -1225,8 +1232,9 @@ fn parseDependentDylibs(self: *MachO) !void { |
| 1225 | 1232 | |
| 1226 | 1233 | try checked_paths.append(try arena.dupe(u8, id.name)); |
| 1227 | 1234 | var buffer: [fs.max_path_bytes]u8 = undefined; |
| 1228 | if (fs.realpath(id.name, &buffer)) |full_path| { | |
| 1229 | break :full_path try arena.dupe(u8, full_path); | |
| 1235 | // TODO don't use realpath | |
| 1236 | if (Io.Dir.realPathAbsolute(io, id.name, &buffer)) |full_path_n| { | |
| 1237 | break :full_path try arena.dupe(u8, buffer[0..full_path_n]); | |
| 1230 | 1238 | } else |_| { |
| 1231 | 1239 | try self.reportMissingDependencyError( |
| 1232 | 1240 | self.getFile(dylib_index).?.dylib.getUmbrella(self).index, |
| ... | ... | @@ -1248,7 +1256,7 @@ fn parseDependentDylibs(self: *MachO) !void { |
| 1248 | 1256 | const fat_arch = try self.parseFatFile(file, lib.path); |
| 1249 | 1257 | const offset = if (fat_arch) |fa| fa.offset else 0; |
| 1250 | 1258 | const file_index = file_index: { |
| 1251 | if (readMachHeader(file, offset) catch null) |h| blk: { | |
| 1259 | if (readMachHeader(io, file, offset) catch null) |h| blk: { | |
| 1252 | 1260 | if (h.magic != macho.MH_MAGIC_64) break :blk; |
| 1253 | 1261 | switch (h.filetype) { |
| 1254 | 1262 | macho.MH_DYLIB => break :file_index try self.addDylib(lib, false, fh, offset), |
| ... | ... | @@ -3244,21 +3252,36 @@ pub fn findFreeSpaceVirtual(self: *MachO, object_size: u64, min_alignment: u32) |
| 3244 | 3252 | } |
| 3245 | 3253 | |
| 3246 | 3254 | pub fn copyRangeAll(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void { |
| 3247 | const file = self.base.file.?; | |
| 3248 | const amt = try file.copyRangeAll(old_offset, file, new_offset, size); | |
| 3249 | if (amt != size) return error.InputOutput; | |
| 3255 | return self.base.copyRangeAll(old_offset, new_offset, size); | |
| 3250 | 3256 | } |
| 3251 | 3257 | |
| 3252 | /// Like File.copyRangeAll but also ensures the source region is zeroed out after copy. | |
| 3258 | /// Like copyRangeAll but also ensures the source region is zeroed out after copy. | |
| 3253 | 3259 | /// This is so that we guarantee zeroed out regions for mapping of zerofill sections by the loader. |
| 3254 | 3260 | fn copyRangeAllZeroOut(self: *MachO, old_offset: u64, new_offset: u64, size: u64) !void { |
| 3255 | const gpa = self.base.comp.gpa; | |
| 3256 | try self.copyRangeAll(old_offset, new_offset, size); | |
| 3261 | const comp = self.base.comp; | |
| 3262 | const io = comp.io; | |
| 3263 | const file = self.base.file.?; | |
| 3264 | var write_buffer: [2048]u8 = undefined; | |
| 3265 | var file_reader = file.reader(io, &.{}); | |
| 3266 | file_reader.pos = old_offset; | |
| 3267 | var file_writer = file.writer(io, &write_buffer); | |
| 3268 | file_writer.pos = new_offset; | |
| 3257 | 3269 | const size_u = math.cast(usize, size) orelse return error.Overflow; |
| 3258 | const zeroes = try gpa.alloc(u8, size_u); // TODO no need to allocate here. | |
| 3259 | defer gpa.free(zeroes); | |
| 3260 | @memset(zeroes, 0); | |
| 3261 | try self.base.file.?.pwriteAll(zeroes, old_offset); | |
| 3270 | const n = file_writer.interface.sendFileAll(&file_reader, .limited(size_u)) catch |err| switch (err) { | |
| 3271 | error.ReadFailed => return file_reader.err.?, | |
| 3272 | error.WriteFailed => return file_writer.err.?, | |
| 3273 | }; | |
| 3274 | assert(n == size_u); | |
| 3275 | file_writer.seekTo(old_offset) catch |err| switch (err) { | |
| 3276 | error.WriteFailed => return file_writer.err.?, | |
| 3277 | else => |e| return e, | |
| 3278 | }; | |
| 3279 | file_writer.interface.splatByteAll(0, size_u) catch |err| switch (err) { | |
| 3280 | error.WriteFailed => return file_writer.err.?, | |
| 3281 | }; | |
| 3282 | file_writer.interface.flush() catch |err| switch (err) { | |
| 3283 | error.WriteFailed => return file_writer.err.?, | |
| 3284 | }; | |
| 3262 | 3285 | } |
| 3263 | 3286 | |
| 3264 | 3287 | const InitMetadataOptions = struct { |
| ... | ... | @@ -5355,10 +5378,10 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { |
| 5355 | 5378 | |
| 5356 | 5379 | pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void { |
| 5357 | 5380 | const comp = macho_file.base.comp; |
| 5381 | const io = comp.io; | |
| 5358 | 5382 | const diags = &comp.link_diags; |
| 5359 | macho_file.base.file.?.pwriteAll(bytes, offset) catch |err| { | |
| 5360 | return diags.fail("failed to write: {s}", .{@errorName(err)}); | |
| 5361 | }; | |
| 5383 | macho_file.base.file.?.writePositionalAll(io, bytes, offset) catch |err| | |
| 5384 | return diags.fail("failed to write: {t}", .{err}); | |
| 5362 | 5385 | } |
| 5363 | 5386 | |
| 5364 | 5387 | pub fn setLength(macho_file: *MachO, length: u64) error{LinkFailure}!void { |
src/link/MachO/Archive.zig+2-2| ... | ... | @@ -24,7 +24,7 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File |
| 24 | 24 | |
| 25 | 25 | var hdr_buffer: [@sizeOf(ar_hdr)]u8 = undefined; |
| 26 | 26 | { |
| 27 | const amt = try handle.preadAll(&hdr_buffer, pos); | |
| 27 | const amt = try handle.readPositionalAll(io, &hdr_buffer, pos); | |
| 28 | 28 | if (amt != @sizeOf(ar_hdr)) return error.InputOutput; |
| 29 | 29 | } |
| 30 | 30 | const hdr = @as(*align(1) const ar_hdr, @ptrCast(&hdr_buffer)).*; |
| ... | ... | @@ -42,7 +42,7 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File |
| 42 | 42 | if (try hdr.nameLength()) |len| { |
| 43 | 43 | hdr_size -= len; |
| 44 | 44 | const buf = try arena.allocator().alloc(u8, len); |
| 45 | const amt = try handle.preadAll(buf, pos); | |
| 45 | const amt = try handle.readPositionalAll(io, buf, pos); | |
| 46 | 46 | if (amt != len) return error.InputOutput; |
| 47 | 47 | pos += len; |
| 48 | 48 | const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len; |
src/link/MachO/DebugSymbols.zig+15-20| ... | ... | @@ -135,20 +135,12 @@ pub fn growSection( |
| 135 | 135 | const new_offset = try self.findFreeSpace(needed_size, 1); |
| 136 | 136 | |
| 137 | 137 | log.debug("moving {s} section: {} bytes from 0x{x} to 0x{x}", .{ |
| 138 | sect.sectName(), | |
| 139 | existing_size, | |
| 140 | sect.offset, | |
| 141 | new_offset, | |
| 138 | sect.sectName(), existing_size, sect.offset, new_offset, | |
| 142 | 139 | }); |
| 143 | 140 | |
| 144 | 141 | if (requires_file_copy) { |
| 145 | const amt = try self.file.?.copyRangeAll( | |
| 146 | sect.offset, | |
| 147 | self.file.?, | |
| 148 | new_offset, | |
| 149 | existing_size, | |
| 150 | ); | |
| 151 | if (amt != existing_size) return error.InputOutput; | |
| 142 | const file = self.file.?; | |
| 143 | try link.File.copyRangeAll2(io, file, file, sect.offset, new_offset, existing_size); | |
| 152 | 144 | } |
| 153 | 145 | |
| 154 | 146 | sect.offset = @intCast(new_offset); |
| ... | ... | @@ -204,6 +196,7 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) !u64 |
| 204 | 196 | } |
| 205 | 197 | |
| 206 | 198 | pub fn flush(self: *DebugSymbols, macho_file: *MachO) !void { |
| 199 | const io = self.io; | |
| 207 | 200 | const zo = macho_file.getZigObject().?; |
| 208 | 201 | for (self.relocs.items) |*reloc| { |
| 209 | 202 | const sym = zo.symbols.items[reloc.target]; |
| ... | ... | @@ -215,12 +208,9 @@ pub fn flush(self: *DebugSymbols, macho_file: *MachO) !void { |
| 215 | 208 | const sect = &self.sections.items[self.debug_info_section_index.?]; |
| 216 | 209 | const file_offset = sect.offset + reloc.offset; |
| 217 | 210 | log.debug("resolving relocation: {d}@{x} ('{s}') at offset {x}", .{ |
| 218 | reloc.target, | |
| 219 | addr, | |
| 220 | sym_name, | |
| 221 | file_offset, | |
| 211 | reloc.target, addr, sym_name, file_offset, | |
| 222 | 212 | }); |
| 223 | try self.file.?.pwriteAll(mem.asBytes(&addr), file_offset); | |
| 213 | try self.file.?.writePositionalAll(io, mem.asBytes(&addr), file_offset); | |
| 224 | 214 | } |
| 225 | 215 | |
| 226 | 216 | self.finalizeDwarfSegment(macho_file); |
| ... | ... | @@ -294,6 +284,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void { |
| 294 | 284 | } |
| 295 | 285 | |
| 296 | 286 | fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } { |
| 287 | const io = self.io; | |
| 297 | 288 | const gpa = self.allocator; |
| 298 | 289 | const needed_size = load_commands.calcLoadCommandsSizeDsym(macho_file, self); |
| 299 | 290 | const buffer = try gpa.alloc(u8, needed_size); |
| ... | ... | @@ -345,12 +336,13 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u |
| 345 | 336 | |
| 346 | 337 | assert(writer.end == needed_size); |
| 347 | 338 | |
| 348 | try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); | |
| 339 | try self.file.?.writePositionalAll(io, buffer, @sizeOf(macho.mach_header_64)); | |
| 349 | 340 | |
| 350 | 341 | return .{ ncmds, buffer.len }; |
| 351 | 342 | } |
| 352 | 343 | |
| 353 | 344 | fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { |
| 345 | const io = self.io; | |
| 354 | 346 | var header: macho.mach_header_64 = .{}; |
| 355 | 347 | header.filetype = macho.MH_DSYM; |
| 356 | 348 | |
| ... | ... | @@ -371,7 +363,7 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds |
| 371 | 363 | |
| 372 | 364 | log.debug("writing Mach-O header {}", .{header}); |
| 373 | 365 | |
| 374 | try self.file.?.pwriteAll(mem.asBytes(&header), 0); | |
| 366 | try self.file.?.writePositionalAll(io, mem.asBytes(&header), 0); | |
| 375 | 367 | } |
| 376 | 368 | |
| 377 | 369 | fn allocatedSize(self: *DebugSymbols, start: u64) u64 { |
| ... | ... | @@ -406,6 +398,8 @@ fn writeLinkeditSegmentData(self: *DebugSymbols, macho_file: *MachO) !void { |
| 406 | 398 | pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 { |
| 407 | 399 | const tracy = trace(@src()); |
| 408 | 400 | defer tracy.end(); |
| 401 | ||
| 402 | const io = self.io; | |
| 409 | 403 | const gpa = self.allocator; |
| 410 | 404 | const cmd = &self.symtab_cmd; |
| 411 | 405 | cmd.nsyms = macho_file.symtab_cmd.nsyms; |
| ... | ... | @@ -429,15 +423,16 @@ pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 { |
| 429 | 423 | internal.writeSymtab(macho_file, self); |
| 430 | 424 | } |
| 431 | 425 | |
| 432 | try self.file.?.pwriteAll(@ptrCast(self.symtab.items), cmd.symoff); | |
| 426 | try self.file.?.writePositionalAll(io, @ptrCast(self.symtab.items), cmd.symoff); | |
| 433 | 427 | |
| 434 | 428 | return off + cmd.nsyms * @sizeOf(macho.nlist_64); |
| 435 | 429 | } |
| 436 | 430 | |
| 437 | 431 | pub fn writeStrtab(self: *DebugSymbols, off: u32) !u32 { |
| 432 | const io = self.io; | |
| 438 | 433 | const cmd = &self.symtab_cmd; |
| 439 | 434 | cmd.stroff = off; |
| 440 | try self.file.?.pwriteAll(self.strtab.items, cmd.stroff); | |
| 435 | try self.file.?.writePositionalAll(io, self.strtab.items, cmd.stroff); | |
| 441 | 436 | return off + cmd.strsize; |
| 442 | 437 | } |
| 443 | 438 |
src/link/MachO/Dylib.zig+12-8| ... | ... | @@ -57,7 +57,9 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void { |
| 57 | 57 | const tracy = trace(@src()); |
| 58 | 58 | defer tracy.end(); |
| 59 | 59 | |
| 60 | const gpa = macho_file.base.comp.gpa; | |
| 60 | const comp = macho_file.base.comp; | |
| 61 | const io = comp.io; | |
| 62 | const gpa = comp.gpa; | |
| 61 | 63 | const file = macho_file.getFileHandle(self.file_handle); |
| 62 | 64 | const offset = self.offset; |
| 63 | 65 | |
| ... | ... | @@ -65,7 +67,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void { |
| 65 | 67 | |
| 66 | 68 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; |
| 67 | 69 | { |
| 68 | const amt = try file.preadAll(&header_buffer, offset); | |
| 70 | const amt = try file.readPositionalAll(io, &header_buffer, offset); | |
| 69 | 71 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; |
| 70 | 72 | } |
| 71 | 73 | const header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; |
| ... | ... | @@ -86,7 +88,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void { |
| 86 | 88 | const lc_buffer = try gpa.alloc(u8, header.sizeofcmds); |
| 87 | 89 | defer gpa.free(lc_buffer); |
| 88 | 90 | { |
| 89 | const amt = try file.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64)); | |
| 91 | const amt = try file.readPositionalAll(io, lc_buffer, offset + @sizeOf(macho.mach_header_64)); | |
| 90 | 92 | if (amt != lc_buffer.len) return error.InputOutput; |
| 91 | 93 | } |
| 92 | 94 | |
| ... | ... | @@ -103,7 +105,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void { |
| 103 | 105 | const dyld_cmd = cmd.cast(macho.dyld_info_command).?; |
| 104 | 106 | const data = try gpa.alloc(u8, dyld_cmd.export_size); |
| 105 | 107 | defer gpa.free(data); |
| 106 | const amt = try file.preadAll(data, dyld_cmd.export_off + offset); | |
| 108 | const amt = try file.readPositionalAll(io, data, dyld_cmd.export_off + offset); | |
| 107 | 109 | if (amt != data.len) return error.InputOutput; |
| 108 | 110 | try self.parseTrie(data, macho_file); |
| 109 | 111 | }, |
| ... | ... | @@ -111,7 +113,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void { |
| 111 | 113 | const ld_cmd = cmd.cast(macho.linkedit_data_command).?; |
| 112 | 114 | const data = try gpa.alloc(u8, ld_cmd.datasize); |
| 113 | 115 | defer gpa.free(data); |
| 114 | const amt = try file.preadAll(data, ld_cmd.dataoff + offset); | |
| 116 | const amt = try file.readPositionalAll(io, data, ld_cmd.dataoff + offset); | |
| 115 | 117 | if (amt != data.len) return error.InputOutput; |
| 116 | 118 | try self.parseTrie(data, macho_file); |
| 117 | 119 | }, |
| ... | ... | @@ -238,13 +240,15 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void { |
| 238 | 240 | const tracy = trace(@src()); |
| 239 | 241 | defer tracy.end(); |
| 240 | 242 | |
| 241 | const gpa = macho_file.base.comp.gpa; | |
| 243 | const comp = macho_file.base.comp; | |
| 244 | const gpa = comp.gpa; | |
| 245 | const io = comp.io; | |
| 242 | 246 | |
| 243 | 247 | log.debug("parsing dylib from stub: {f}", .{self.path}); |
| 244 | 248 | |
| 245 | 249 | const file = macho_file.getFileHandle(self.file_handle); |
| 246 | var lib_stub = LibStub.loadFromFile(gpa, file) catch |err| { | |
| 247 | try macho_file.reportParseError2(self.index, "failed to parse TBD file: {s}", .{@errorName(err)}); | |
| 250 | var lib_stub = LibStub.loadFromFile(gpa, io, file) catch |err| { | |
| 251 | try macho_file.reportParseError2(self.index, "failed to parse TBD file: {t}", .{err}); | |
| 248 | 252 | return error.MalformedTbd; |
| 249 | 253 | }; |
| 250 | 254 | defer lib_stub.deinit(); |
src/link/MachO/Object.zig+88-61| ... | ... | @@ -1,3 +1,30 @@ |
| 1 | const Object = @This(); | |
| 2 | ||
| 3 | const trace = @import("../../tracy.zig").trace; | |
| 4 | const Archive = @import("Archive.zig"); | |
| 5 | const Atom = @import("Atom.zig"); | |
| 6 | const Dwarf = @import("Dwarf.zig"); | |
| 7 | const File = @import("file.zig").File; | |
| 8 | const MachO = @import("../MachO.zig"); | |
| 9 | const Relocation = @import("Relocation.zig"); | |
| 10 | const Symbol = @import("Symbol.zig"); | |
| 11 | const UnwindInfo = @import("UnwindInfo.zig"); | |
| 12 | ||
| 13 | const std = @import("std"); | |
| 14 | const Io = std.Io; | |
| 15 | const Writer = std.Io.Writer; | |
| 16 | const assert = std.debug.assert; | |
| 17 | const log = std.log.scoped(.link); | |
| 18 | const macho = std.macho; | |
| 19 | const LoadCommandIterator = macho.LoadCommandIterator; | |
| 20 | const math = std.math; | |
| 21 | const mem = std.mem; | |
| 22 | const Allocator = std.mem.Allocator; | |
| 23 | ||
| 24 | const eh_frame = @import("eh_frame.zig"); | |
| 25 | const Cie = eh_frame.Cie; | |
| 26 | const Fde = eh_frame.Fde; | |
| 27 | ||
| 1 | 28 | /// Non-zero for fat object files or archives |
| 2 | 29 | offset: u64, |
| 3 | 30 | /// If `in_archive` is not `null`, this is the basename of the object in the archive. Otherwise, |
| ... | ... | @@ -75,7 +102,9 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 75 | 102 | |
| 76 | 103 | log.debug("parsing {f}", .{self.fmtPath()}); |
| 77 | 104 | |
| 78 | const gpa = macho_file.base.comp.gpa; | |
| 105 | const comp = macho_file.base.comp; | |
| 106 | const io = comp.io; | |
| 107 | const gpa = comp.gpa; | |
| 79 | 108 | const handle = macho_file.getFileHandle(self.file_handle); |
| 80 | 109 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 81 | 110 | |
| ... | ... | @@ -84,7 +113,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 84 | 113 | |
| 85 | 114 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; |
| 86 | 115 | { |
| 87 | const amt = try handle.preadAll(&header_buffer, self.offset); | |
| 116 | const amt = try handle.readPositionalAll(io, &header_buffer, self.offset); | |
| 88 | 117 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; |
| 89 | 118 | } |
| 90 | 119 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; |
| ... | ... | @@ -105,7 +134,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 105 | 134 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); |
| 106 | 135 | defer gpa.free(lc_buffer); |
| 107 | 136 | { |
| 108 | const amt = try handle.preadAll(lc_buffer, self.offset + @sizeOf(macho.mach_header_64)); | |
| 137 | const amt = try handle.readPositionalAll(io, lc_buffer, self.offset + @sizeOf(macho.mach_header_64)); | |
| 109 | 138 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; |
| 110 | 139 | } |
| 111 | 140 | |
| ... | ... | @@ -129,14 +158,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 129 | 158 | const cmd = lc.cast(macho.symtab_command).?; |
| 130 | 159 | try self.strtab.resize(gpa, cmd.strsize); |
| 131 | 160 | { |
| 132 | const amt = try handle.preadAll(self.strtab.items, cmd.stroff + self.offset); | |
| 161 | const amt = try handle.readPositionalAll(io, self.strtab.items, cmd.stroff + self.offset); | |
| 133 | 162 | if (amt != self.strtab.items.len) return error.InputOutput; |
| 134 | 163 | } |
| 135 | 164 | |
| 136 | 165 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); |
| 137 | 166 | defer gpa.free(symtab_buffer); |
| 138 | 167 | { |
| 139 | const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset); | |
| 168 | const amt = try handle.readPositionalAll(io, symtab_buffer, cmd.symoff + self.offset); | |
| 140 | 169 | if (amt != symtab_buffer.len) return error.InputOutput; |
| 141 | 170 | } |
| 142 | 171 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; |
| ... | ... | @@ -154,7 +183,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 154 | 183 | const buffer = try gpa.alloc(u8, cmd.datasize); |
| 155 | 184 | defer gpa.free(buffer); |
| 156 | 185 | { |
| 157 | const amt = try handle.preadAll(buffer, self.offset + cmd.dataoff); | |
| 186 | const amt = try handle.readPositionalAll(io, buffer, self.offset + cmd.dataoff); | |
| 158 | 187 | if (amt != buffer.len) return error.InputOutput; |
| 159 | 188 | } |
| 160 | 189 | const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry)); |
| ... | ... | @@ -440,12 +469,14 @@ fn initCstringLiterals(self: *Object, allocator: Allocator, file: File.Handle, m |
| 440 | 469 | const tracy = trace(@src()); |
| 441 | 470 | defer tracy.end(); |
| 442 | 471 | |
| 472 | const comp = macho_file.base.comp; | |
| 473 | const io = comp.io; | |
| 443 | 474 | const slice = self.sections.slice(); |
| 444 | 475 | |
| 445 | 476 | for (slice.items(.header), 0..) |sect, n_sect| { |
| 446 | 477 | if (!isCstringLiteral(sect)) continue; |
| 447 | 478 | |
| 448 | const data = try self.readSectionData(allocator, file, @intCast(n_sect)); | |
| 479 | const data = try self.readSectionData(allocator, io, file, @intCast(n_sect)); | |
| 449 | 480 | defer allocator.free(data); |
| 450 | 481 | |
| 451 | 482 | var count: u32 = 0; |
| ... | ... | @@ -628,7 +659,9 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO |
| 628 | 659 | const tracy = trace(@src()); |
| 629 | 660 | defer tracy.end(); |
| 630 | 661 | |
| 631 | const gpa = macho_file.base.comp.gpa; | |
| 662 | const comp = macho_file.base.comp; | |
| 663 | const io = comp.io; | |
| 664 | const gpa = comp.gpa; | |
| 632 | 665 | const file = macho_file.getFileHandle(self.file_handle); |
| 633 | 666 | |
| 634 | 667 | var buffer = std.array_list.Managed(u8).init(gpa); |
| ... | ... | @@ -647,7 +680,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO |
| 647 | 680 | const slice = self.sections.slice(); |
| 648 | 681 | for (slice.items(.header), slice.items(.subsections), 0..) |header, subs, n_sect| { |
| 649 | 682 | if (isCstringLiteral(header) or isFixedSizeLiteral(header)) { |
| 650 | const data = try self.readSectionData(gpa, file, @intCast(n_sect)); | |
| 683 | const data = try self.readSectionData(gpa, io, file, @intCast(n_sect)); | |
| 651 | 684 | defer gpa.free(data); |
| 652 | 685 | |
| 653 | 686 | for (subs.items) |sub| { |
| ... | ... | @@ -682,7 +715,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO |
| 682 | 715 | buffer.resize(target_size) catch unreachable; |
| 683 | 716 | const gop = try sections_data.getOrPut(target.n_sect); |
| 684 | 717 | if (!gop.found_existing) { |
| 685 | gop.value_ptr.* = try self.readSectionData(gpa, file, @intCast(target.n_sect)); | |
| 718 | gop.value_ptr.* = try self.readSectionData(gpa, io, file, @intCast(target.n_sect)); | |
| 686 | 719 | } |
| 687 | 720 | const data = gop.value_ptr.*; |
| 688 | 721 | const target_off = try macho_file.cast(usize, target.off); |
| ... | ... | @@ -1037,9 +1070,11 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi |
| 1037 | 1070 | const sect = slice.items(.header)[sect_id]; |
| 1038 | 1071 | const relocs = slice.items(.relocs)[sect_id]; |
| 1039 | 1072 | |
| 1073 | const comp = macho_file.base.comp; | |
| 1074 | const io = comp.io; | |
| 1040 | 1075 | const size = try macho_file.cast(usize, sect.size); |
| 1041 | 1076 | try self.eh_frame_data.resize(allocator, size); |
| 1042 | const amt = try file.preadAll(self.eh_frame_data.items, sect.offset + self.offset); | |
| 1077 | const amt = try file.readPositionalAll(io, self.eh_frame_data.items, sect.offset + self.offset); | |
| 1043 | 1078 | if (amt != self.eh_frame_data.items.len) return error.InputOutput; |
| 1044 | 1079 | |
| 1045 | 1080 | // Check for non-personality relocs in FDEs and apply them |
| ... | ... | @@ -1138,8 +1173,10 @@ fn initUnwindRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fil |
| 1138 | 1173 | } |
| 1139 | 1174 | }; |
| 1140 | 1175 | |
| 1176 | const comp = macho_file.base.comp; | |
| 1177 | const io = comp.io; | |
| 1141 | 1178 | const header = self.sections.items(.header)[sect_id]; |
| 1142 | const data = try self.readSectionData(allocator, file, sect_id); | |
| 1179 | const data = try self.readSectionData(allocator, io, file, sect_id); | |
| 1143 | 1180 | defer allocator.free(data); |
| 1144 | 1181 | |
| 1145 | 1182 | const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry)); |
| ... | ... | @@ -1348,7 +1385,9 @@ fn parseDebugInfo(self: *Object, macho_file: *MachO) !void { |
| 1348 | 1385 | const tracy = trace(@src()); |
| 1349 | 1386 | defer tracy.end(); |
| 1350 | 1387 | |
| 1351 | const gpa = macho_file.base.comp.gpa; | |
| 1388 | const comp = macho_file.base.comp; | |
| 1389 | const io = comp.io; | |
| 1390 | const gpa = comp.gpa; | |
| 1352 | 1391 | const file = macho_file.getFileHandle(self.file_handle); |
| 1353 | 1392 | |
| 1354 | 1393 | var dwarf: Dwarf = .{}; |
| ... | ... | @@ -1358,18 +1397,18 @@ fn parseDebugInfo(self: *Object, macho_file: *MachO) !void { |
| 1358 | 1397 | const n_sect: u8 = @intCast(index); |
| 1359 | 1398 | if (sect.attrs() & macho.S_ATTR_DEBUG == 0) continue; |
| 1360 | 1399 | if (mem.eql(u8, sect.sectName(), "__debug_info")) { |
| 1361 | dwarf.debug_info = try self.readSectionData(gpa, file, n_sect); | |
| 1400 | dwarf.debug_info = try self.readSectionData(gpa, io, file, n_sect); | |
| 1362 | 1401 | } |
| 1363 | 1402 | if (mem.eql(u8, sect.sectName(), "__debug_abbrev")) { |
| 1364 | dwarf.debug_abbrev = try self.readSectionData(gpa, file, n_sect); | |
| 1403 | dwarf.debug_abbrev = try self.readSectionData(gpa, io, file, n_sect); | |
| 1365 | 1404 | } |
| 1366 | 1405 | if (mem.eql(u8, sect.sectName(), "__debug_str")) { |
| 1367 | dwarf.debug_str = try self.readSectionData(gpa, file, n_sect); | |
| 1406 | dwarf.debug_str = try self.readSectionData(gpa, io, file, n_sect); | |
| 1368 | 1407 | } |
| 1369 | 1408 | // __debug_str_offs[ets] section is a new addition in DWARFv5 and is generally |
| 1370 | 1409 | // required in order to correctly parse strings. |
| 1371 | 1410 | if (mem.eql(u8, sect.sectName(), "__debug_str_offs")) { |
| 1372 | dwarf.debug_str_offsets = try self.readSectionData(gpa, file, n_sect); | |
| 1411 | dwarf.debug_str_offsets = try self.readSectionData(gpa, io, file, n_sect); | |
| 1373 | 1412 | } |
| 1374 | 1413 | } |
| 1375 | 1414 | |
| ... | ... | @@ -1611,12 +1650,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1611 | 1650 | const tracy = trace(@src()); |
| 1612 | 1651 | defer tracy.end(); |
| 1613 | 1652 | |
| 1614 | const gpa = macho_file.base.comp.gpa; | |
| 1653 | const comp = macho_file.base.comp; | |
| 1654 | const io = comp.io; | |
| 1655 | const gpa = comp.gpa; | |
| 1615 | 1656 | const handle = macho_file.getFileHandle(self.file_handle); |
| 1616 | 1657 | |
| 1617 | 1658 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; |
| 1618 | 1659 | { |
| 1619 | const amt = try handle.preadAll(&header_buffer, self.offset); | |
| 1660 | const amt = try handle.readPositionalAll(io, &header_buffer, self.offset); | |
| 1620 | 1661 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; |
| 1621 | 1662 | } |
| 1622 | 1663 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; |
| ... | ... | @@ -1637,7 +1678,7 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1637 | 1678 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); |
| 1638 | 1679 | defer gpa.free(lc_buffer); |
| 1639 | 1680 | { |
| 1640 | const amt = try handle.preadAll(lc_buffer, self.offset + @sizeOf(macho.mach_header_64)); | |
| 1681 | const amt = try handle.readPositionalAll(io, lc_buffer, self.offset + @sizeOf(macho.mach_header_64)); | |
| 1641 | 1682 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; |
| 1642 | 1683 | } |
| 1643 | 1684 | |
| ... | ... | @@ -1647,14 +1688,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { |
| 1647 | 1688 | const cmd = lc.cast(macho.symtab_command).?; |
| 1648 | 1689 | try self.strtab.resize(gpa, cmd.strsize); |
| 1649 | 1690 | { |
| 1650 | const amt = try handle.preadAll(self.strtab.items, cmd.stroff + self.offset); | |
| 1691 | const amt = try handle.readPositionalAll(io, self.strtab.items, cmd.stroff + self.offset); | |
| 1651 | 1692 | if (amt != self.strtab.items.len) return error.InputOutput; |
| 1652 | 1693 | } |
| 1653 | 1694 | |
| 1654 | 1695 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); |
| 1655 | 1696 | defer gpa.free(symtab_buffer); |
| 1656 | 1697 | { |
| 1657 | const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset); | |
| 1698 | const amt = try handle.readPositionalAll(io, symtab_buffer, cmd.symoff + self.offset); | |
| 1658 | 1699 | if (amt != symtab_buffer.len) return error.InputOutput; |
| 1659 | 1700 | } |
| 1660 | 1701 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; |
| ... | ... | @@ -1697,7 +1738,7 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { |
| 1697 | 1738 | }; |
| 1698 | 1739 | } |
| 1699 | 1740 | |
| 1700 | pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { | |
| 1741 | pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: *Writer) !void { | |
| 1701 | 1742 | // Header |
| 1702 | 1743 | const size = try macho_file.cast(usize, self.output_ar_state.size); |
| 1703 | 1744 | const basename = std.fs.path.basename(self.path); |
| ... | ... | @@ -1705,10 +1746,12 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ |
| 1705 | 1746 | // Data |
| 1706 | 1747 | const file = macho_file.getFileHandle(self.file_handle); |
| 1707 | 1748 | // TODO try using copyRangeAll |
| 1708 | const gpa = macho_file.base.comp.gpa; | |
| 1749 | const comp = macho_file.base.comp; | |
| 1750 | const io = comp.io; | |
| 1751 | const gpa = comp.gpa; | |
| 1709 | 1752 | const data = try gpa.alloc(u8, size); |
| 1710 | 1753 | defer gpa.free(data); |
| 1711 | const amt = try file.preadAll(data, self.offset); | |
| 1754 | const amt = try file.readPositionalAll(io, data, self.offset); | |
| 1712 | 1755 | if (amt != size) return error.InputOutput; |
| 1713 | 1756 | try writer.writeAll(data); |
| 1714 | 1757 | } |
| ... | ... | @@ -1813,7 +1856,9 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void { |
| 1813 | 1856 | const tracy = trace(@src()); |
| 1814 | 1857 | defer tracy.end(); |
| 1815 | 1858 | |
| 1816 | const gpa = macho_file.base.comp.gpa; | |
| 1859 | const comp = macho_file.base.comp; | |
| 1860 | const io = comp.io; | |
| 1861 | const gpa = comp.gpa; | |
| 1817 | 1862 | const headers = self.sections.items(.header); |
| 1818 | 1863 | const sections_data = try gpa.alloc([]const u8, headers.len); |
| 1819 | 1864 | defer { |
| ... | ... | @@ -1829,7 +1874,7 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void { |
| 1829 | 1874 | if (header.isZerofill()) continue; |
| 1830 | 1875 | const size = try macho_file.cast(usize, header.size); |
| 1831 | 1876 | const data = try gpa.alloc(u8, size); |
| 1832 | const amt = try file.preadAll(data, header.offset + self.offset); | |
| 1877 | const amt = try file.readPositionalAll(io, data, header.offset + self.offset); | |
| 1833 | 1878 | if (amt != data.len) return error.InputOutput; |
| 1834 | 1879 | sections_data[n_sect] = data; |
| 1835 | 1880 | } |
| ... | ... | @@ -1852,7 +1897,9 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void { |
| 1852 | 1897 | const tracy = trace(@src()); |
| 1853 | 1898 | defer tracy.end(); |
| 1854 | 1899 | |
| 1855 | const gpa = macho_file.base.comp.gpa; | |
| 1900 | const comp = macho_file.base.comp; | |
| 1901 | const io = comp.io; | |
| 1902 | const gpa = comp.gpa; | |
| 1856 | 1903 | const headers = self.sections.items(.header); |
| 1857 | 1904 | const sections_data = try gpa.alloc([]const u8, headers.len); |
| 1858 | 1905 | defer { |
| ... | ... | @@ -1868,7 +1915,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void { |
| 1868 | 1915 | if (header.isZerofill()) continue; |
| 1869 | 1916 | const size = try macho_file.cast(usize, header.size); |
| 1870 | 1917 | const data = try gpa.alloc(u8, size); |
| 1871 | const amt = try file.preadAll(data, header.offset + self.offset); | |
| 1918 | const amt = try file.readPositionalAll(io, data, header.offset + self.offset); | |
| 1872 | 1919 | if (amt != data.len) return error.InputOutput; |
| 1873 | 1920 | sections_data[n_sect] = data; |
| 1874 | 1921 | } |
| ... | ... | @@ -2484,11 +2531,11 @@ pub fn getUnwindRecord(self: *Object, index: UnwindInfo.Record.Index) *UnwindInf |
| 2484 | 2531 | } |
| 2485 | 2532 | |
| 2486 | 2533 | /// Caller owns the memory. |
| 2487 | pub fn readSectionData(self: Object, allocator: Allocator, file: File.Handle, n_sect: u8) ![]u8 { | |
| 2534 | pub fn readSectionData(self: Object, allocator: Allocator, io: Io, file: File.Handle, n_sect: u8) ![]u8 { | |
| 2488 | 2535 | const header = self.sections.items(.header)[n_sect]; |
| 2489 | 2536 | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2490 | 2537 | const data = try allocator.alloc(u8, size); |
| 2491 | const amt = try file.preadAll(data, header.offset + self.offset); | |
| 2538 | const amt = try file.readPositionalAll(io, data, header.offset + self.offset); | |
| 2492 | 2539 | errdefer allocator.free(data); |
| 2493 | 2540 | if (amt != data.len) return error.InputOutput; |
| 2494 | 2541 | return data; |
| ... | ... | @@ -2712,15 +2759,17 @@ const x86_64 = struct { |
| 2712 | 2759 | handle: File.Handle, |
| 2713 | 2760 | macho_file: *MachO, |
| 2714 | 2761 | ) !void { |
| 2715 | const gpa = macho_file.base.comp.gpa; | |
| 2762 | const comp = macho_file.base.comp; | |
| 2763 | const io = comp.io; | |
| 2764 | const gpa = comp.gpa; | |
| 2716 | 2765 | |
| 2717 | 2766 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 2718 | 2767 | defer gpa.free(relocs_buffer); |
| 2719 | const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset); | |
| 2768 | const amt = try handle.readPositionalAll(io, relocs_buffer, sect.reloff + self.offset); | |
| 2720 | 2769 | if (amt != relocs_buffer.len) return error.InputOutput; |
| 2721 | 2770 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; |
| 2722 | 2771 | |
| 2723 | const code = try self.readSectionData(gpa, handle, n_sect); | |
| 2772 | const code = try self.readSectionData(gpa, io, handle, n_sect); | |
| 2724 | 2773 | defer gpa.free(code); |
| 2725 | 2774 | |
| 2726 | 2775 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); |
| ... | ... | @@ -2879,15 +2928,17 @@ const aarch64 = struct { |
| 2879 | 2928 | handle: File.Handle, |
| 2880 | 2929 | macho_file: *MachO, |
| 2881 | 2930 | ) !void { |
| 2882 | const gpa = macho_file.base.comp.gpa; | |
| 2931 | const comp = macho_file.base.comp; | |
| 2932 | const io = comp.io; | |
| 2933 | const gpa = comp.gpa; | |
| 2883 | 2934 | |
| 2884 | 2935 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 2885 | 2936 | defer gpa.free(relocs_buffer); |
| 2886 | const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset); | |
| 2937 | const amt = try handle.readPositionalAll(io, relocs_buffer, sect.reloff + self.offset); | |
| 2887 | 2938 | if (amt != relocs_buffer.len) return error.InputOutput; |
| 2888 | 2939 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; |
| 2889 | 2940 | |
| 2890 | const code = try self.readSectionData(gpa, handle, n_sect); | |
| 2941 | const code = try self.readSectionData(gpa, io, handle, n_sect); | |
| 2891 | 2942 | defer gpa.free(code); |
| 2892 | 2943 | |
| 2893 | 2944 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); |
| ... | ... | @@ -3063,27 +3114,3 @@ const aarch64 = struct { |
| 3063 | 3114 | } |
| 3064 | 3115 | } |
| 3065 | 3116 | }; |
| 3066 | ||
| 3067 | const std = @import("std"); | |
| 3068 | const assert = std.debug.assert; | |
| 3069 | const log = std.log.scoped(.link); | |
| 3070 | const macho = std.macho; | |
| 3071 | const math = std.math; | |
| 3072 | const mem = std.mem; | |
| 3073 | const Allocator = std.mem.Allocator; | |
| 3074 | const Writer = std.Io.Writer; | |
| 3075 | ||
| 3076 | const eh_frame = @import("eh_frame.zig"); | |
| 3077 | const trace = @import("../../tracy.zig").trace; | |
| 3078 | const Archive = @import("Archive.zig"); | |
| 3079 | const Atom = @import("Atom.zig"); | |
| 3080 | const Cie = eh_frame.Cie; | |
| 3081 | const Dwarf = @import("Dwarf.zig"); | |
| 3082 | const Fde = eh_frame.Fde; | |
| 3083 | const File = @import("file.zig").File; | |
| 3084 | const LoadCommandIterator = macho.LoadCommandIterator; | |
| 3085 | const MachO = @import("../MachO.zig"); | |
| 3086 | const Object = @This(); | |
| 3087 | const Relocation = @import("Relocation.zig"); | |
| 3088 | const Symbol = @import("Symbol.zig"); | |
| 3089 | const UnwindInfo = @import("UnwindInfo.zig"); |
src/link/MachO/ZigObject.zig+14-7| ... | ... | @@ -171,6 +171,9 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 |
| 171 | 171 | const isec = atom.getInputSection(macho_file); |
| 172 | 172 | assert(!isec.isZerofill()); |
| 173 | 173 | |
| 174 | const comp = macho_file.base.comp; | |
| 175 | const io = comp.io; | |
| 176 | ||
| 174 | 177 | switch (isec.type()) { |
| 175 | 178 | macho.S_THREAD_LOCAL_REGULAR => { |
| 176 | 179 | const tlv = self.tlv_initializers.get(atom.atom_index).?; |
| ... | ... | @@ -182,7 +185,7 @@ pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8 |
| 182 | 185 | else => { |
| 183 | 186 | const sect = macho_file.sections.items(.header)[atom.out_n_sect]; |
| 184 | 187 | const file_offset = sect.offset + atom.value; |
| 185 | const amt = try macho_file.base.file.?.preadAll(buffer, file_offset); | |
| 188 | const amt = try macho_file.base.file.?.readPositionalAll(io, buffer, file_offset); | |
| 186 | 189 | if (amt != buffer.len) return error.InputOutput; |
| 187 | 190 | }, |
| 188 | 191 | } |
| ... | ... | @@ -290,12 +293,14 @@ pub fn dedupLiterals(self: *ZigObject, lp: MachO.LiteralPool, macho_file: *MachO |
| 290 | 293 | /// We need this so that we can write to an archive. |
| 291 | 294 | /// TODO implement writing ZigObject data directly to a buffer instead. |
| 292 | 295 | pub fn readFileContents(self: *ZigObject, macho_file: *MachO) !void { |
| 293 | const diags = &macho_file.base.comp.link_diags; | |
| 296 | const comp = macho_file.base.comp; | |
| 297 | const gpa = comp.gpa; | |
| 298 | const io = comp.io; | |
| 299 | const diags = &comp.link_diags; | |
| 294 | 300 | // Size of the output object file is always the offset + size of the strtab |
| 295 | 301 | const size = macho_file.symtab_cmd.stroff + macho_file.symtab_cmd.strsize; |
| 296 | const gpa = macho_file.base.comp.gpa; | |
| 297 | 302 | try self.data.resize(gpa, size); |
| 298 | const amt = macho_file.base.file.?.preadAll(self.data.items, 0) catch |err| | |
| 303 | const amt = macho_file.base.file.?.readPositionalAll(io, self.data.items, 0) catch |err| | |
| 299 | 304 | return diags.fail("failed to read output file: {s}", .{@errorName(err)}); |
| 300 | 305 | if (amt != size) |
| 301 | 306 | return diags.fail("unexpected EOF reading from output file", .{}); |
| ... | ... | @@ -945,6 +950,8 @@ fn updateNavCode( |
| 945 | 950 | ) link.File.UpdateNavError!void { |
| 946 | 951 | const zcu = pt.zcu; |
| 947 | 952 | const gpa = zcu.gpa; |
| 953 | const comp = zcu.comp; | |
| 954 | const io = comp.io; | |
| 948 | 955 | const ip = &zcu.intern_pool; |
| 949 | 956 | const nav = ip.getNav(nav_index); |
| 950 | 957 | |
| ... | ... | @@ -1012,8 +1019,8 @@ fn updateNavCode( |
| 1012 | 1019 | |
| 1013 | 1020 | if (!sect.isZerofill()) { |
| 1014 | 1021 | const file_offset = sect.offset + atom.value; |
| 1015 | macho_file.base.file.?.pwriteAll(code, file_offset) catch |err| | |
| 1016 | return macho_file.base.cgFail(nav_index, "failed to write output file: {s}", .{@errorName(err)}); | |
| 1022 | macho_file.base.file.?.writePositionalAll(io, code, file_offset) catch |err| | |
| 1023 | return macho_file.base.cgFail(nav_index, "failed to write output file: {t}", .{err}); | |
| 1017 | 1024 | } |
| 1018 | 1025 | } |
| 1019 | 1026 | |
| ... | ... | @@ -1493,7 +1500,7 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, macho_file: *MachO) !void { |
| 1493 | 1500 | .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf), |
| 1494 | 1501 | else => @panic("TODO implement write trampoline for this CPU arch"), |
| 1495 | 1502 | }; |
| 1496 | try macho_file.base.file.?.pwriteAll(out, fileoff); | |
| 1503 | return macho_file.pwriteAll(out, fileoff); | |
| 1497 | 1504 | } |
| 1498 | 1505 | |
| 1499 | 1506 | pub fn getOrCreateMetadataForNav( |
src/link/MachO/fat.zig+6-6| ... | ... | @@ -10,13 +10,13 @@ const mem = std.mem; |
| 10 | 10 | |
| 11 | 11 | const MachO = @import("../MachO.zig"); |
| 12 | 12 | |
| 13 | pub fn readFatHeader(file: Io.File) !macho.fat_header { | |
| 14 | return readFatHeaderGeneric(macho.fat_header, file, 0); | |
| 13 | pub fn readFatHeader(io: Io, file: Io.File) !macho.fat_header { | |
| 14 | return readFatHeaderGeneric(io, macho.fat_header, file, 0); | |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | fn readFatHeaderGeneric(comptime Hdr: type, file: Io.File, offset: usize) !Hdr { | |
| 17 | fn readFatHeaderGeneric(io: Io, comptime Hdr: type, file: Io.File, offset: usize) !Hdr { | |
| 18 | 18 | var buffer: [@sizeOf(Hdr)]u8 = undefined; |
| 19 | const nread = try file.preadAll(&buffer, offset); | |
| 19 | const nread = try file.readPositionalAll(io, &buffer, offset); | |
| 20 | 20 | if (nread != buffer.len) return error.InputOutput; |
| 21 | 21 | var hdr = @as(*align(1) const Hdr, @ptrCast(&buffer)).*; |
| 22 | 22 | mem.byteSwapAllFields(Hdr, &hdr); |
| ... | ... | @@ -29,12 +29,12 @@ pub const Arch = struct { |
| 29 | 29 | size: u32, |
| 30 | 30 | }; |
| 31 | 31 | |
| 32 | pub fn parseArchs(file: Io.File, fat_header: macho.fat_header, out: *[2]Arch) ![]const Arch { | |
| 32 | pub fn parseArchs(io: Io, file: Io.File, fat_header: macho.fat_header, out: *[2]Arch) ![]const Arch { | |
| 33 | 33 | var count: usize = 0; |
| 34 | 34 | var fat_arch_index: u32 = 0; |
| 35 | 35 | while (fat_arch_index < fat_header.nfat_arch and count < out.len) : (fat_arch_index += 1) { |
| 36 | 36 | const offset = @sizeOf(macho.fat_header) + @sizeOf(macho.fat_arch) * fat_arch_index; |
| 37 | const fat_arch = try readFatHeaderGeneric(macho.fat_arch, file, offset); | |
| 37 | const fat_arch = try readFatHeaderGeneric(io, macho.fat_arch, file, offset); | |
| 38 | 38 | // If we come across an architecture that we do not know how to handle, that's |
| 39 | 39 | // fine because we can keep looking for one that might match. |
| 40 | 40 | const arch: std.Target.Cpu.Arch = switch (fat_arch.cputype) { |
src/link/MachO/hasher.zig+9-9| ... | ... | @@ -9,7 +9,7 @@ pub fn ParallelHasher(comptime Hasher: type) type { |
| 9 | 9 | const hash_size = Hasher.digest_length; |
| 10 | 10 | |
| 11 | 11 | return struct { |
| 12 | pub fn hash(self: Self, io: Io, file: Io.File, out: [][hash_size]u8, opts: struct { | |
| 12 | pub fn hash(gpa: Allocator, io: Io, file: Io.File, out: [][hash_size]u8, opts: struct { | |
| 13 | 13 | chunk_size: u64 = 0x4000, |
| 14 | 14 | max_file_size: ?u64 = null, |
| 15 | 15 | }) !void { |
| ... | ... | @@ -22,11 +22,11 @@ pub fn ParallelHasher(comptime Hasher: type) type { |
| 22 | 22 | }; |
| 23 | 23 | const chunk_size = std.math.cast(usize, opts.chunk_size) orelse return error.Overflow; |
| 24 | 24 | |
| 25 | const buffer = try self.allocator.alloc(u8, chunk_size * out.len); | |
| 26 | defer self.allocator.free(buffer); | |
| 25 | const buffer = try gpa.alloc(u8, chunk_size * out.len); | |
| 26 | defer gpa.free(buffer); | |
| 27 | 27 | |
| 28 | const results = try self.allocator.alloc(Io.File.ReadPositionalError!usize, out.len); | |
| 29 | defer self.allocator.free(results); | |
| 28 | const results = try gpa.alloc(Io.File.ReadPositionalError!usize, out.len); | |
| 29 | defer gpa.free(results); | |
| 30 | 30 | |
| 31 | 31 | { |
| 32 | 32 | var group: Io.Group = .init; |
| ... | ... | @@ -38,7 +38,8 @@ pub fn ParallelHasher(comptime Hasher: type) type { |
| 38 | 38 | file_size - fstart |
| 39 | 39 | else |
| 40 | 40 | chunk_size; |
| 41 | group.async(worker, .{ | |
| 41 | group.async(io, worker, .{ | |
| 42 | io, | |
| 42 | 43 | file, |
| 43 | 44 | fstart, |
| 44 | 45 | buffer[fstart..][0..fsize], |
| ... | ... | @@ -53,16 +54,15 @@ pub fn ParallelHasher(comptime Hasher: type) type { |
| 53 | 54 | } |
| 54 | 55 | |
| 55 | 56 | fn worker( |
| 57 | io: Io, | |
| 56 | 58 | file: Io.File, |
| 57 | 59 | fstart: usize, |
| 58 | 60 | buffer: []u8, |
| 59 | 61 | out: *[hash_size]u8, |
| 60 | 62 | err: *Io.File.ReadPositionalError!usize, |
| 61 | 63 | ) void { |
| 62 | err.* = file.readPositionalAll(buffer, fstart); | |
| 64 | err.* = file.readPositionalAll(io, buffer, fstart); | |
| 63 | 65 | Hasher.hash(buffer, out, .{}); |
| 64 | 66 | } |
| 65 | ||
| 66 | const Self = @This(); | |
| 67 | 67 | }; |
| 68 | 68 | } |
src/link/MachO/relocatable.zig+9-11| ... | ... | @@ -10,10 +10,10 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat |
| 10 | 10 | positionals.appendSliceAssumeCapacity(comp.link_inputs); |
| 11 | 11 | |
| 12 | 12 | for (comp.c_object_table.keys()) |key| { |
| 13 | try positionals.append(try link.openObjectInput(diags, key.status.success.object_path)); | |
| 13 | try positionals.append(try link.openObjectInput(io, diags, key.status.success.object_path)); | |
| 14 | 14 | } |
| 15 | 15 | |
| 16 | if (module_obj_path) |path| try positionals.append(try link.openObjectInput(diags, path)); | |
| 16 | if (module_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path)); | |
| 17 | 17 | |
| 18 | 18 | if (macho_file.getZigObject() == null and positionals.items.len == 1) { |
| 19 | 19 | // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all |
| ... | ... | @@ -24,10 +24,8 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat |
| 24 | 24 | return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) }); |
| 25 | 25 | const stat = in_file.stat(io) catch |err| |
| 26 | 26 | return diags.fail("failed to stat {f}: {s}", .{ path, @errorName(err) }); |
| 27 | const amt = in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size) catch |err| | |
| 28 | return diags.fail("failed to copy range of file {f}: {s}", .{ path, @errorName(err) }); | |
| 29 | if (amt != stat.size) | |
| 30 | return diags.fail("unexpected short write in copy range of file {f}", .{path}); | |
| 27 | link.File.copyRangeAll2(io, in_file, macho_file.base.file.?, 0, 0, stat.size) catch |err| | |
| 28 | return diags.fail("failed to copy range of file {f}: {t}", .{ path, err }); | |
| 31 | 29 | return; |
| 32 | 30 | } |
| 33 | 31 | |
| ... | ... | @@ -90,17 +88,17 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 90 | 88 | positionals.appendSliceAssumeCapacity(comp.link_inputs); |
| 91 | 89 | |
| 92 | 90 | for (comp.c_object_table.keys()) |key| { |
| 93 | try positionals.append(try link.openObjectInput(diags, key.status.success.object_path)); | |
| 91 | try positionals.append(try link.openObjectInput(io, diags, key.status.success.object_path)); | |
| 94 | 92 | } |
| 95 | 93 | |
| 96 | if (module_obj_path) |path| try positionals.append(try link.openObjectInput(diags, path)); | |
| 94 | if (module_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path)); | |
| 97 | 95 | |
| 98 | 96 | if (comp.compiler_rt_strat == .obj) { |
| 99 | try positionals.append(try link.openObjectInput(diags, comp.compiler_rt_obj.?.full_object_path)); | |
| 97 | try positionals.append(try link.openObjectInput(io, diags, comp.compiler_rt_obj.?.full_object_path)); | |
| 100 | 98 | } |
| 101 | 99 | |
| 102 | 100 | if (comp.ubsan_rt_strat == .obj) { |
| 103 | try positionals.append(try link.openObjectInput(diags, comp.ubsan_rt_obj.?.full_object_path)); | |
| 101 | try positionals.append(try link.openObjectInput(io, diags, comp.ubsan_rt_obj.?.full_object_path)); | |
| 104 | 102 | } |
| 105 | 103 | |
| 106 | 104 | for (positionals.items) |link_input| { |
| ... | ... | @@ -231,7 +229,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 231 | 229 | |
| 232 | 230 | assert(writer.end == total_size); |
| 233 | 231 | |
| 234 | try macho_file.setLength(io, total_size); | |
| 232 | try macho_file.setLength(total_size); | |
| 235 | 233 | try macho_file.pwriteAll(writer.buffered(), 0); |
| 236 | 234 | |
| 237 | 235 | if (diags.hasErrors()) return error.LinkFailure; |
src/link/SpirV.zig+3-2| ... | ... | @@ -246,6 +246,7 @@ pub fn flush( |
| 246 | 246 | const comp = linker.base.comp; |
| 247 | 247 | const diags = &comp.link_diags; |
| 248 | 248 | const gpa = comp.gpa; |
| 249 | const io = comp.io; | |
| 249 | 250 | |
| 250 | 251 | // We need to export the list of error names somewhere so that we can pretty-print them in the |
| 251 | 252 | // executor. This is not really an important thing though, so we can just dump it in any old |
| ... | ... | @@ -287,8 +288,8 @@ pub fn flush( |
| 287 | 288 | }; |
| 288 | 289 | |
| 289 | 290 | // TODO endianness bug. use file writer and call writeSliceEndian instead |
| 290 | linker.base.file.?.writeAll(@ptrCast(linked_module)) catch |err| | |
| 291 | return diags.fail("failed to write: {s}", .{@errorName(err)}); | |
| 291 | linker.base.file.?.writeStreamingAll(io, @ptrCast(linked_module)) catch |err| | |
| 292 | return diags.fail("failed to write: {t}", .{err}); | |
| 292 | 293 | } |
| 293 | 294 | |
| 294 | 295 | fn linkModule(arena: Allocator, module: []Word, progress: std.Progress.Node) ![]Word { |
src/link/Wasm.zig+4-2| ... | ... | @@ -3016,8 +3016,10 @@ pub fn createEmpty( |
| 3016 | 3016 | } |
| 3017 | 3017 | |
| 3018 | 3018 | fn openParseObjectReportingFailure(wasm: *Wasm, path: Path) void { |
| 3019 | const diags = &wasm.base.comp.link_diags; | |
| 3020 | const obj = link.openObject(path, false, false) catch |err| { | |
| 3019 | const comp = wasm.base.comp; | |
| 3020 | const io = comp.io; | |
| 3021 | const diags = &comp.link_diags; | |
| 3022 | const obj = link.openObject(io, path, false, false) catch |err| { | |
| 3021 | 3023 | switch (diags.failParse(path, "failed to open object: {t}", .{err})) { |
| 3022 | 3024 | error.LinkFailure => return, |
| 3023 | 3025 | } |
src/link/Wasm/Flush.zig+2-1| ... | ... | @@ -108,6 +108,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void { |
| 108 | 108 | |
| 109 | 109 | pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 110 | 110 | const comp = wasm.base.comp; |
| 111 | const io = comp.io; | |
| 111 | 112 | const shared_memory = comp.config.shared_memory; |
| 112 | 113 | const diags = &comp.link_diags; |
| 113 | 114 | const gpa = comp.gpa; |
| ... | ... | @@ -1067,7 +1068,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 1067 | 1068 | } |
| 1068 | 1069 | |
| 1069 | 1070 | // Finally, write the entire binary into the file. |
| 1070 | var file_writer = wasm.base.file.?.writer(&.{}); | |
| 1071 | var file_writer = wasm.base.file.?.writer(io, &.{}); | |
| 1071 | 1072 | file_writer.interface.writeAll(binary_bytes.items) catch |err| switch (err) { |
| 1072 | 1073 | error.WriteFailed => return file_writer.err.?, |
| 1073 | 1074 | }; |
src/link/tapi.zig+2-2| ... | ... | @@ -130,7 +130,7 @@ pub const Tbd = union(enum) { |
| 130 | 130 | pub const TapiError = error{ |
| 131 | 131 | NotLibStub, |
| 132 | 132 | InputOutput, |
| 133 | } || yaml.YamlError || Io.File.PReadError; | |
| 133 | } || yaml.YamlError || Io.File.ReadPositionalError; | |
| 134 | 134 | |
| 135 | 135 | pub const LibStub = struct { |
| 136 | 136 | /// Underlying memory for stub's contents. |
| ... | ... | @@ -146,7 +146,7 @@ pub const LibStub = struct { |
| 146 | 146 | }; |
| 147 | 147 | const source = try allocator.alloc(u8, filesize); |
| 148 | 148 | defer allocator.free(source); |
| 149 | const amt = try file.preadAll(source, 0); | |
| 149 | const amt = try file.readPositionalAll(io, source, 0); | |
| 150 | 150 | if (amt != filesize) return error.InputOutput; |
| 151 | 151 | |
| 152 | 152 | var lib_stub = LibStub{ |
src/main.zig+1-1| ... | ... | @@ -3677,7 +3677,7 @@ fn buildOutputType( |
| 3677 | 3677 | } |
| 3678 | 3678 | |
| 3679 | 3679 | { |
| 3680 | const root_prog_node = std.Progress.start(.{ | |
| 3680 | const root_prog_node = std.Progress.start(io, .{ | |
| 3681 | 3681 | .disable_printing = (color == .off), |
| 3682 | 3682 | }); |
| 3683 | 3683 | defer root_prog_node.end(); |