authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-12 16:30:44-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:09-08:00
log54e4a3456ce2d5a497a166b94737fe5407052921
tree28721a6cfc8d522d59c98b8583c53a33b04aa94b
parent22b0eea3c0a2d2088ea6823d1de4ea5d9da6260d

link: update to new file system APIs


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};
494494/// See also:
495495/// * `writer`
496496pub 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.
501pub 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);
498505}
499506
500507pub const SeekError = error{
src/link.zig+46-10
......@@ -620,7 +620,7 @@ pub const File = struct {
620620 emit.sub_path, std.crypto.random.int(u32),
621621 });
622622 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, .{});
624624 try emit.root_dir.handle.rename(tmp_sub_path, emit.root_dir.handle, emit.sub_path, io);
625625 switch (builtin.os.tag) {
626626 .linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
......@@ -852,10 +852,12 @@ pub const File = struct {
852852 }
853853 }
854854
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;
859861 }
860862 }
861863
......@@ -908,6 +910,7 @@ pub const File = struct {
908910 /// `arena` has the lifetime of the call to `Compilation.update`.
909911 pub fn flush(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void {
910912 const comp = base.comp;
913 const io = comp.io;
911914 if (comp.clang_preprocessor_mode == .yes or comp.clang_preprocessor_mode == .pch) {
912915 dev.check(.clang_command);
913916 const emit = base.emit;
......@@ -918,12 +921,19 @@ pub const File = struct {
918921 assert(comp.c_object_table.count() == 1);
919922 const the_key = comp.c_object_table.keys()[0];
920923 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| {
922932 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}", .{
924934 std.fmt.alt(@as(Path, cached_pp_file_path), .formatEscapeChar),
925935 std.fmt.alt(@as(Path, emit), .formatEscapeChar),
926 @errorName(err),
936 err,
927937 });
928938 };
929939 return;
......@@ -1119,7 +1129,7 @@ pub const File = struct {
11191129 const size = std.math.cast(u32, stat.size) orelse return error.FileTooBig;
11201130 const buf = try gpa.alloc(u8, size);
11211131 defer gpa.free(buf);
1122 const n = try file.preadAll(buf, 0);
1132 const n = try file.readPositionalAll(io, buf, 0);
11231133 if (buf.len != n) return error.UnexpectedEndOfFile;
11241134 var ld_script = try LdScript.parse(gpa, diags, path, buf);
11251135 defer ld_script.deinit(gpa);
......@@ -1184,6 +1194,32 @@ pub const File = struct {
11841194 }
11851195 }
11861196
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
11871223 pub const Tag = enum {
11881224 coff2,
11891225 elf,
......@@ -1243,7 +1279,7 @@ pub const File = struct {
12431279 // with 0o755 permissions, but it works appropriately if the system is configured
12441280 // more leniently. As another data point, C's fopen seems to open files with the
12451281 // 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)
12471283 .default_file
12481284 else
12491285 .fromMode(0o777);
src/link/Coff.zig+24-23
......@@ -1,3 +1,22 @@
1const Coff = @This();
2
3const builtin = @import("builtin");
4const native_endian = builtin.cpu.arch.endian();
5
6const std = @import("std");
7const assert = std.debug.assert;
8const log = std.log.scoped(.link);
9
10const codegen = @import("../codegen.zig");
11const Compilation = @import("../Compilation.zig");
12const InternPool = @import("../InternPool.zig");
13const link = @import("../link.zig");
14const MappedFile = @import("MappedFile.zig");
15const target_util = @import("../target.zig");
16const Type = @import("../Type.zig");
17const Value = @import("../Value.zig");
18const Zcu = @import("../Zcu.zig");
19
120base: link.File,
221mf: MappedFile,
322nodes: std.MultiArrayList(Node),
......@@ -1729,22 +1748,20 @@ pub fn flush(
17291748 const comp = coff.base.comp;
17301749 if (comp.compiler_rt_dyn_lib) |crt_file| {
17311750 const gpa = comp.gpa;
1751 const io = comp.io;
17321752 const compiler_rt_sub_path = try std.fs.path.join(gpa, &.{
17331753 std.fs.path.dirname(coff.base.emit.sub_path) orelse "",
17341754 std.fs.path.basename(crt_file.full_object_path.sub_path),
17351755 });
17361756 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,
17381759 crt_file.full_object_path.sub_path,
17391760 coff.base.emit.root_dir.handle,
17401761 compiler_rt_sub_path,
1762 io,
17411763 .{},
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 });
17481765 }
17491766}
17501767
......@@ -2461,19 +2478,3 @@ pub fn printNode(
24612478 }
24622479 }
24632480}
2464
2465const assert = std.debug.assert;
2466const builtin = @import("builtin");
2467const codegen = @import("../codegen.zig");
2468const Compilation = @import("../Compilation.zig");
2469const Coff = @This();
2470const InternPool = @import("../InternPool.zig");
2471const link = @import("../link.zig");
2472const log = std.log.scoped(.link);
2473const MappedFile = @import("MappedFile.zig");
2474const native_endian = builtin.cpu.arch.endian();
2475const std = @import("std");
2476const target_util = @import("../target.zig");
2477const Type = @import("../Type.zig");
2478const Value = @import("../Value.zig");
2479const Zcu = @import("../Zcu.zig");
src/link/Dwarf.zig+35-20
......@@ -48,6 +48,7 @@ pub const UpdateError = error{
4848 EndOfStream,
4949 Underflow,
5050 UnexpectedEndOfFile,
51 NonResizable,
5152} ||
5253 codegen.GenerateSymbolError ||
5354 Io.File.OpenError ||
......@@ -155,11 +156,14 @@ const DebugInfo = struct {
155156
156157 fn declAbbrevCode(debug_info: *DebugInfo, unit: Unit.Index, entry: Entry.Index) !AbbrevCode {
157158 const dwarf: *Dwarf = @fieldParentPtr("debug_info", debug_info);
159 const comp = dwarf.bin_file.comp;
160 const io = comp.io;
158161 const unit_ptr = debug_info.section.getUnit(unit);
159162 const entry_ptr = unit_ptr.getEntry(entry);
160163 if (entry_ptr.len < AbbrevCode.decl_bytes) return .null;
161164 var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined;
162 if (try dwarf.getFile().?.preadAll(
165 if (try dwarf.getFile().?.readPositionalAll(
166 io,
163167 &abbrev_code_buf,
164168 debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
165169 ) != abbrev_code_buf.len) return error.InputOutput;
......@@ -639,13 +643,10 @@ const Unit = struct {
639643
640644 fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void {
641645 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);
649650 unit.off = new_off;
650651 }
651652
......@@ -675,10 +676,14 @@ const Unit = struct {
675676
676677 fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
677678 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);
679682 }
680683
681684 fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
685 const comp = dwarf.bin_file.comp;
686 const io = comp.io;
682687 const start = unit.off + unit.header_len + if (unit.last.unwrap()) |last_entry| end: {
683688 const last_entry_ptr = unit.getEntry(last_entry);
684689 break :end last_entry_ptr.off + last_entry_ptr.len;
......@@ -708,7 +713,7 @@ const Unit = struct {
708713 assert(fw.end == extended_op_bytes + op_len_bytes);
709714 fw.writeByte(DW.LNE.padding) catch unreachable;
710715 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);
712717 }
713718 var trailer_aw: Writer.Allocating = try .initCapacity(dwarf.gpa, len);
714719 defer trailer_aw.deinit();
......@@ -768,7 +773,7 @@ const Unit = struct {
768773 assert(tw.end == unit.trailer_len);
769774 tw.splatByteAll(fill_byte, len - unit.trailer_len) catch unreachable;
770775 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);
772777 }
773778
774779 fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void {
......@@ -854,6 +859,8 @@ const Entry = struct {
854859 dwarf: *Dwarf,
855860 ) (UpdateError || Writer.Error)!void {
856861 assert(entry.len > 0);
862 const comp = dwarf.bin_file.comp;
863 const io = comp.io;
857864 const start = entry.off + entry.len;
858865 if (sec == &dwarf.debug_frame.section) {
859866 const len = if (entry.next.unwrap()) |next_entry|
......@@ -863,11 +870,11 @@ const Entry = struct {
863870 var unit_len_buf: [8]u8 = undefined;
864871 const unit_len_bytes = unit_len_buf[0..dwarf.sectionOffsetBytes()];
865872 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);
867874 const buf = try dwarf.gpa.alloc(u8, len - entry.len);
868875 defer dwarf.gpa.free(buf);
869876 @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);
871878 return;
872879 }
873880 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
......@@ -926,7 +933,7 @@ const Entry = struct {
926933 },
927934 } else assert(!sec.pad_entries_to_ideal and len == 0);
928935 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);
930937 }
931938
932939 fn resize(
......@@ -969,11 +976,13 @@ const Entry = struct {
969976
970977 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
971978 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);
973982 if (false) {
974983 const buf = try dwarf.gpa.alloc(u8, sec.len);
975984 defer dwarf.gpa.free(buf);
976 _ = try dwarf.getFile().?.preadAll(buf, sec.off(dwarf));
985 _ = try dwarf.getFile().?.readPositionalAll(io, buf, sec.off(dwarf));
977986 log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{
978987 @intFromEnum(sec.first),
979988 @intFromEnum(sec.last),
......@@ -4702,6 +4711,8 @@ fn updateContainerTypeWriterError(
47024711}
47034712
47044713pub 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;
47054716 const ip = &zcu.intern_pool;
47064717
47074718 const inst_info = zir_index.resolveFull(ip).?;
......@@ -4721,7 +4732,7 @@ pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedI
47214732
47224733 const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return);
47234734 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));
47254736}
47264737
47274738pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {
......@@ -4758,6 +4769,8 @@ pub fn flush(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
47584769fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Error)!void {
47594770 const zcu = pt.zcu;
47604771 const ip = &zcu.intern_pool;
4772 const comp = dwarf.bin_file.comp;
4773 const io = comp.io;
47614774
47624775 {
47634776 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
49774990 if (dwarf.debug_str.section.dirty) {
49784991 const contents = dwarf.debug_str.contents.items;
49794992 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));
49814994 dwarf.debug_str.section.dirty = false;
49824995 }
49834996 if (dwarf.debug_line.section.dirty) {
......@@ -5089,7 +5102,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Erro
50895102 if (dwarf.debug_line_str.section.dirty) {
50905103 const contents = dwarf.debug_line_str.contents.items;
50915104 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));
50935106 dwarf.debug_line_str.section.dirty = false;
50945107 }
50955108 if (dwarf.debug_loclists.section.dirty) {
......@@ -6411,9 +6424,11 @@ fn writeInt(dwarf: *Dwarf, buf: []u8, int: u64) void {
64116424}
64126425
64136426fn resolveReloc(dwarf: *Dwarf, source: u64, target: u64, size: u32) RelocError!void {
6427 const comp = dwarf.bin_file.comp;
6428 const io = comp.io;
64146429 var buf: [8]u8 = undefined;
64156430 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);
64176432}
64186433
64196434fn 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:
582582 new_offset,
583583 });
584584
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);
593586
594587 shdr.sh_offset = new_offset;
595588 } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
......@@ -745,7 +738,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
745738 .res => unreachable,
746739 .dso_exact => @panic("TODO"),
747740 .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),
749742 .dso => |dso| try parseDso(gpa, io, diags, dso, &self.shared_objects, &self.files, target),
750743 }
751744}
......@@ -1055,9 +1048,11 @@ fn dumpArgvInit(self: *Elf, arena: Allocator) !void {
10551048}
10561049
10571050pub 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})) {
10611056 error.LinkFailure => return,
10621057 }
10631058 };
......@@ -1065,10 +1060,11 @@ pub fn openParseObjectReportingFailure(self: *Elf, path: Path) void {
10651060}
10661061
10671062fn 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;
10691065 self.parseObject(obj) catch |err| switch (err) {
10701066 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}),
10721068 };
10731069}
10741070
......@@ -1076,10 +1072,12 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void {
10761072 const tracy = trace(@src());
10771073 defer tracy.end();
10781074
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;
10831081 const default_sym_version = self.default_sym_version;
10841082 const file_handles = &self.file_handles;
10851083
......@@ -1098,14 +1096,15 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void {
10981096 try self.objects.append(gpa, index);
10991097
11001098 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);
11021100 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);
11041102 }
11051103}
11061104
11071105fn parseArchive(
11081106 gpa: Allocator,
1107 io: Io,
11091108 diags: *Diags,
11101109 file_handles: *std.ArrayList(File.Handle),
11111110 files: *std.MultiArrayList(File.Entry),
......@@ -1120,7 +1119,7 @@ fn parseArchive(
11201119 defer tracy.end();
11211120
11221121 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);
11241123 defer archive.deinit(gpa);
11251124
11261125 const init_alive = if (is_static_lib) true else obj.must_link;
......@@ -1131,9 +1130,9 @@ fn parseArchive(
11311130 const object = &files.items(.data)[index].object;
11321131 object.index = index;
11331132 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);
11351134 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);
11371136 try objects.append(gpa, index);
11381137 }
11391138}
......@@ -1153,7 +1152,7 @@ fn parseDso(
11531152 const handle = dso.file;
11541153
11551154 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);
11571156 defer header.deinit(gpa);
11581157
11591158 const soname = header.soname() orelse dso.path.basename();
......@@ -1167,7 +1166,7 @@ fn parseDso(
11671166
11681167 gop.value_ptr.* = index;
11691168
1170 var parsed = try SharedObject.parse(gpa, &header, handle);
1169 var parsed = try SharedObject.parse(gpa, io, &header, handle);
11711170 errdefer parsed.deinit(gpa);
11721171
11731172 const duped_path: Path = .{
......@@ -2897,13 +2896,7 @@ pub fn allocateAllocSections(self: *Elf) !void {
28972896 if (shdr.sh_offset > 0) {
28982897 // Get size actually commited to the output file.
28992898 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);
29072900 }
29082901
29092902 shdr.sh_offset = new_offset;
......@@ -2939,13 +2932,7 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
29392932
29402933 if (shdr.sh_offset > 0) {
29412934 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);
29492936 }
29502937
29512938 shdr.sh_offset = new_offset;
......@@ -4075,10 +4062,10 @@ fn fmtDumpState(self: *Elf, writer: *std.Io.Writer) std.Io.Writer.Error!void {
40754062}
40764063
40774064/// Caller owns the memory.
4078pub fn preadAllAlloc(allocator: Allocator, handle: Io.File, offset: u64, size: u64) ![]u8 {
4065pub fn preadAllAlloc(allocator: Allocator, io: Io, io_file: Io.File, offset: u64, size: u64) ![]u8 {
40794066 const buffer = try allocator.alloc(u8, math.cast(usize, size) orelse return error.Overflow);
40804067 errdefer allocator.free(buffer);
4081 const amt = try handle.preadAll(buffer, offset);
4068 const amt = try io_file.readPositionalAll(io, buffer, offset);
40824069 if (amt != size) return error.InputOutput;
40834070 return buffer;
40844071}
......@@ -4444,10 +4431,10 @@ pub fn stringTableLookup(strtab: []const u8, off: u32) [:0]const u8 {
44444431
44454432pub fn pwriteAll(elf_file: *Elf, bytes: []const u8, offset: u64) error{LinkFailure}!void {
44464433 const comp = elf_file.base.comp;
4434 const io = comp.io;
44474435 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});
44514438}
44524439
44534440pub fn setLength(elf_file: *Elf, length: u64) error{LinkFailure}!void {
src/link/Elf/Archive.zig+5-5
......@@ -34,17 +34,17 @@ pub fn parse(
3434 path: Path,
3535 handle_index: File.HandleIndex,
3636) !Archive {
37 const handle = file_handles.items[handle_index];
37 const file = file_handles.items[handle_index];
3838 var pos: usize = 0;
3939 {
4040 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);
4242 if (n != magic_buffer.len) return error.BadMagic;
4343 if (!mem.eql(u8, &magic_buffer, elf.ARMAG)) return error.BadMagic;
4444 pos += magic_buffer.len;
4545 }
4646
47 const size = (try handle.stat(io)).size;
47 const size = (try file.stat(io)).size;
4848
4949 var objects: std.ArrayList(Object) = .empty;
5050 defer objects.deinit(gpa);
......@@ -55,7 +55,7 @@ pub fn parse(
5555 while (pos < size) {
5656 var hdr: elf.ar_hdr = undefined;
5757 {
58 const n = try handle.preadAll(mem.asBytes(&hdr), pos);
58 const n = try file.readPositionalAll(io, mem.asBytes(&hdr), pos);
5959 if (n != @sizeOf(elf.ar_hdr)) return error.UnexpectedEndOfFile;
6060 }
6161 pos += @sizeOf(elf.ar_hdr);
......@@ -72,7 +72,7 @@ pub fn parse(
7272 if (hdr.isSymtab() or hdr.isSymtab64()) continue;
7373 if (hdr.isStrtab()) {
7474 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);
7676 if (amt != obj_size) return error.InputOutput;
7777 continue;
7878 }
src/link/Elf/AtomList.zig+8-4
......@@ -90,7 +90,9 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
9090}
9191
9292pub 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;
9496 const osec = elf_file.sections.items(.shdr)[list.output_section_index];
9597 assert(osec.sh_type != elf.SHT_NOBITS);
9698 assert(!list.dirty);
......@@ -121,12 +123,14 @@ pub fn write(list: AtomList, buffer: *std.Io.Writer.Allocating, undefs: anytype,
121123 try atom_ptr.resolveRelocsAlloc(elf_file, out_code);
122124 }
123125
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));
125127 buffer.clearRetainingCapacity();
126128}
127129
128130pub 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;
130134 const osec = elf_file.sections.items(.shdr)[list.output_section_index];
131135 assert(osec.sh_type != elf.SHT_NOBITS);
132136
......@@ -152,7 +156,7 @@ pub fn writeRelocatable(list: AtomList, buffer: *std.array_list.Managed(u8), elf
152156 @memcpy(out_code, code);
153157 }
154158
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));
156160 buffer.clearRetainingCapacity();
157161}
158162
src/link/Elf/Object.zig+25-19
......@@ -92,6 +92,7 @@ pub fn deinit(self: *Object, gpa: Allocator) void {
9292pub fn parse(
9393 self: *Object,
9494 gpa: Allocator,
95 io: Io,
9596 diags: *Diags,
9697 /// For error reporting purposes only.
9798 path: Path,
......@@ -105,7 +106,7 @@ pub fn parse(
105106 // Allocate atom index 0 to null atom
106107 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) });
107108
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);
109110 try self.initSymbols(gpa, default_sym_version);
110111
111112 for (self.shdrs.items, 0..) |shdr, i| {
......@@ -114,7 +115,7 @@ pub fn parse(
114115 if ((target.cpu.arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or
115116 mem.eql(u8, self.getString(atom_ptr.name_offset), ".eh_frame"))
116117 {
117 try self.parseEhFrame(gpa, handle, @intCast(i), target);
118 try self.parseEhFrame(gpa, io, handle, @intCast(i), target);
118119 }
119120 }
120121}
......@@ -131,7 +132,7 @@ pub fn parseCommon(
131132 const offset = if (self.archive) |ar| ar.offset else 0;
132133 const file_size = (try handle.stat(io)).size;
133134
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));
135136 defer gpa.free(header_buffer);
136137 self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*;
137138 if (!mem.eql(u8, self.header.?.e_ident[0..4], elf.MAGIC)) {
......@@ -155,7 +156,7 @@ pub fn parseCommon(
155156 return diags.failParse(path, "corrupt header: section header table extends past the end of file", .{});
156157 }
157158
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);
159160 defer gpa.free(shdrs_buffer);
160161 const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum];
161162 try self.shdrs.appendUnalignedSlice(gpa, shdrs);
......@@ -168,7 +169,7 @@ pub fn parseCommon(
168169 }
169170 }
170171
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);
172173 defer gpa.free(shstrtab);
173174 for (self.shdrs.items) |shdr| {
174175 if (shdr.sh_name >= shstrtab.len) {
......@@ -186,7 +187,7 @@ pub fn parseCommon(
186187 const shdr = self.shdrs.items[index];
187188 self.first_global = shdr.sh_info;
188189
189 const raw_symtab = try self.preadShdrContentsAlloc(gpa, handle, index);
190 const raw_symtab = try self.preadShdrContentsAlloc(gpa, io, handle, index);
190191 defer gpa.free(raw_symtab);
191192 const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch {
192193 return diags.failParse(path, "symbol table not evenly divisible", .{});
......@@ -194,7 +195,7 @@ pub fn parseCommon(
194195 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
195196
196197 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);
198199 defer gpa.free(strtab);
199200 try self.strtab.appendSlice(gpa, strtab);
200201
......@@ -290,6 +291,7 @@ pub fn validateEFlags(
290291fn initAtoms(
291292 self: *Object,
292293 gpa: Allocator,
294 io: Io,
293295 diags: *Diags,
294296 path: Path,
295297 handle: Io.File,
......@@ -325,7 +327,7 @@ fn initAtoms(
325327 };
326328
327329 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);
329331 defer gpa.free(group_raw_data);
330332 const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch {
331333 return diags.failParse(path, "corrupt section group: not evenly divisible ", .{});
......@@ -366,7 +368,7 @@ fn initAtoms(
366368 const shndx: u32 = @intCast(i);
367369 if (self.skipShdr(shndx, debug_fmt_strip)) continue;
368370 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);
370372 defer gpa.free(data);
371373 const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
372374 break :blk .{ chdr.ch_size, Alignment.fromNonzeroByteUnits(chdr.ch_addralign) };
......@@ -387,7 +389,7 @@ fn initAtoms(
387389 elf.SHT_REL, elf.SHT_RELA => {
388390 const atom_index = self.atoms_indexes.items[shdr.sh_info];
389391 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));
391393 defer gpa.free(relocs);
392394 atom_ptr.relocs_section_index = @intCast(i);
393395 const rel_index: u32 = @intCast(self.relocs.items.len);
......@@ -449,6 +451,7 @@ fn initSymbols(
449451fn parseEhFrame(
450452 self: *Object,
451453 gpa: Allocator,
454 io: Io,
452455 handle: Io.File,
453456 shndx: u32,
454457 target: *const std.Target,
......@@ -458,12 +461,12 @@ fn parseEhFrame(
458461 else => {},
459462 } else null;
460463
461 const raw = try self.preadShdrContentsAlloc(gpa, handle, shndx);
464 const raw = try self.preadShdrContentsAlloc(gpa, io, handle, shndx);
462465 defer gpa.free(raw);
463466 const data_start: u32 = @intCast(self.eh_frame_data.items.len);
464467 try self.eh_frame_data.appendSlice(gpa, raw);
465468 const relocs = if (relocs_shndx) |index|
466 try self.preadRelocsAlloc(gpa, handle, index)
469 try self.preadRelocsAlloc(gpa, io, handle, index)
467470 else
468471 &[0]elf.Elf64_Rela{};
469472 defer gpa.free(relocs);
......@@ -1132,6 +1135,9 @@ pub fn updateArSize(self: *Object, elf_file: *Elf) !void {
11321135}
11331136
11341137pub 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;
11351141 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
11361142 const offset: u64 = if (self.archive) |ar| ar.offset else 0;
11371143 const name = fs.path.basename(self.path.sub_path);
......@@ -1144,10 +1150,9 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
11441150 });
11451151 try writer.writeAll(mem.asBytes(&hdr));
11461152 const handle = elf_file.fileHandle(self.file_handle);
1147 const gpa = elf_file.base.comp.gpa;
11481153 const data = try gpa.alloc(u8, size);
11491154 defer gpa.free(data);
1150 const amt = try handle.preadAll(data, offset);
1155 const amt = try handle.readPositionalAll(io, data, offset);
11511156 if (amt != size) return error.InputOutput;
11521157 try writer.writeAll(data);
11531158}
......@@ -1220,11 +1225,12 @@ pub fn writeSymtab(self: *Object, elf_file: *Elf) void {
12201225/// Caller owns the memory.
12211226pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
12221227 const comp = elf_file.base.comp;
1228 const io = comp.io;
12231229 const gpa = comp.gpa;
12241230 const atom_ptr = self.atom(atom_index).?;
12251231 const shdr = atom_ptr.inputShdr(elf_file);
12261232 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);
12281234 defer if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) gpa.free(data);
12291235
12301236 if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
......@@ -1340,18 +1346,18 @@ fn addString(self: *Object, gpa: Allocator, str: []const u8) !u32 {
13401346}
13411347
13421348/// Caller owns the memory.
1343fn preadShdrContentsAlloc(self: Object, gpa: Allocator, handle: Io.File, index: u32) ![]u8 {
1349fn preadShdrContentsAlloc(self: Object, gpa: Allocator, io: Io, handle: Io.File, index: u32) ![]u8 {
13441350 assert(index < self.shdrs.items.len);
13451351 const offset = if (self.archive) |ar| ar.offset else 0;
13461352 const shdr = self.shdrs.items[index];
13471353 const sh_offset = math.cast(u64, shdr.sh_offset) orelse return error.Overflow;
13481354 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);
13501356}
13511357
13521358/// Caller owns the memory.
1353fn 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);
1359fn 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);
13551361 const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela));
13561362 return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
13571363}
src/link/Elf/SharedObject.zig+11-9
......@@ -109,16 +109,17 @@ pub const Parsed = struct {
109109
110110pub fn parseHeader(
111111 gpa: Allocator,
112 io: Io,
112113 diags: *Diags,
113114 file_path: Path,
114 fs_file: Io.File,
115 file: Io.File,
115116 stat: Stat,
116117 target: *const std.Target,
117118) !Header {
118119 var ehdr: elf.Elf64_Ehdr = undefined;
119120 {
120121 const buf = mem.asBytes(&ehdr);
121 const amt = try fs_file.preadAll(buf, 0);
122 const amt = try file.readPositionalAll(io, buf, 0);
122123 if (amt != buf.len) return error.UnexpectedEndOfFile;
123124 }
124125 if (!mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")) return error.BadMagic;
......@@ -135,7 +136,7 @@ pub fn parseHeader(
135136 errdefer gpa.free(sections);
136137 {
137138 const buf = mem.sliceAsBytes(sections);
138 const amt = try fs_file.preadAll(buf, shoff);
139 const amt = try file.readPositionalAll(io, buf, shoff);
139140 if (amt != buf.len) return error.UnexpectedEndOfFile;
140141 }
141142
......@@ -160,7 +161,7 @@ pub fn parseHeader(
160161 const dynamic_table = try gpa.alloc(elf.Elf64_Dyn, n);
161162 errdefer gpa.free(dynamic_table);
162163 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);
164165 if (amt != buf.len) return error.UnexpectedEndOfFile;
165166 break :dt dynamic_table;
166167 } else &.{};
......@@ -175,7 +176,7 @@ pub fn parseHeader(
175176 const strtab_shdr = sections[dynsym_shdr.sh_link];
176177 const n = std.math.cast(usize, strtab_shdr.sh_size) orelse return error.Overflow;
177178 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);
179180 if (amt != buf.len) return error.UnexpectedEndOfFile;
180181 }
181182
......@@ -207,9 +208,10 @@ pub fn parseHeader(
207208
208209pub fn parse(
209210 gpa: Allocator,
211 io: Io,
210212 /// Moves resources from header. Caller may unconditionally deinit.
211213 header: *Header,
212 fs_file: Io.File,
214 file: Io.File,
213215) !Parsed {
214216 const symtab = if (header.dynsym_sect_index) |index| st: {
215217 const shdr = header.sections[index];
......@@ -217,7 +219,7 @@ pub fn parse(
217219 const symtab = try gpa.alloc(elf.Elf64_Sym, n);
218220 errdefer gpa.free(symtab);
219221 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);
221223 if (amt != buf.len) return error.UnexpectedEndOfFile;
222224 break :st symtab;
223225 } else &.{};
......@@ -228,7 +230,7 @@ pub fn parse(
228230
229231 if (header.verdef_sect_index) |shndx| {
230232 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);
232234 defer gpa.free(verdefs);
233235
234236 var offset: u32 = 0;
......@@ -254,7 +256,7 @@ pub fn parse(
254256 const versyms = try gpa.alloc(elf.Versym, symtab.len);
255257 errdefer gpa.free(versyms);
256258 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);
258260 if (amt != buf.len) return error.UnexpectedEndOfFile;
259261 break :vs versyms;
260262 } else &.{};
src/link/Elf/ZigObject.zig+19-9
......@@ -740,7 +740,9 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O
740740/// We need this so that we can write to an archive.
741741/// TODO implement writing ZigObject data directly to a buffer instead.
742742pub 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;
744746 const shsize: u64 = switch (elf_file.ptr_width) {
745747 .p32 => @sizeOf(elf.Elf32_Shdr),
746748 .p64 => @sizeOf(elf.Elf64_Shdr),
......@@ -753,7 +755,7 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {
753755 const size = std.math.cast(usize, end_pos) orelse return error.Overflow;
754756 try self.data.resize(gpa, size);
755757
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);
757759 if (amt != size) return error.InputOutput;
758760}
759761
......@@ -901,13 +903,15 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
901903/// Returns atom's code.
902904/// Caller owns the memory.
903905pub 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;
905909 const atom_ptr = self.atom(atom_index).?;
906910 const file_offset = atom_ptr.offset(elf_file);
907911 const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow;
908912 const code = try gpa.alloc(u8, size);
909913 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);
911915 if (amt != code.len) {
912916 log.err("fetching code for {s} failed", .{atom_ptr.name(elf_file)});
913917 return error.InputOutput;
......@@ -1365,6 +1369,8 @@ fn updateNavCode(
13651369) link.File.UpdateNavError!void {
13661370 const zcu = pt.zcu;
13671371 const gpa = zcu.gpa;
1372 const comp = elf_file.base.comp;
1373 const io = comp.io;
13681374 const ip = &zcu.intern_pool;
13691375 const nav = ip.getNav(nav_index);
13701376
......@@ -1449,8 +1455,8 @@ fn updateNavCode(
14491455 const shdr = elf_file.sections.items(.shdr)[shdr_index];
14501456 if (shdr.sh_type != elf.SHT_NOBITS) {
14511457 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});
14541460 log.debug("writing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len });
14551461 }
14561462}
......@@ -1467,6 +1473,8 @@ fn updateTlv(
14671473 const zcu = pt.zcu;
14681474 const ip = &zcu.intern_pool;
14691475 const gpa = zcu.gpa;
1476 const comp = elf_file.base.comp;
1477 const io = comp.io;
14701478 const nav = ip.getNav(nav_index);
14711479
14721480 log.debug("updateTlv {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
......@@ -1503,8 +1511,8 @@ fn updateTlv(
15031511 const shdr = elf_file.sections.items(.shdr)[shndx];
15041512 if (shdr.sh_type != elf.SHT_NOBITS) {
15051513 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});
15081516 log.debug("writing TLV {s} from 0x{x} to 0x{x}", .{
15091517 atom_ptr.name(elf_file),
15101518 file_offset,
......@@ -2003,6 +2011,8 @@ fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 {
20032011}
20042012
20052013fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
2014 const comp = elf_file.base.comp;
2015 const io = comp.io;
20062016 const atom_ptr = tr_sym.atom(elf_file).?;
20072017 const fileoff = atom_ptr.offset(elf_file);
20082018 const source_addr = tr_sym.address(.{}, elf_file);
......@@ -2012,7 +2022,7 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
20122022 .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf),
20132023 else => @panic("TODO implement write trampoline for this CPU arch"),
20142024 };
2015 try elf_file.base.file.?.pwriteAll(out, fileoff);
2025 try elf_file.base.file.?.writePositionalAll(io, out, fileoff);
20162026
20172027 if (elf_file.base.child_pid) |pid| {
20182028 switch (builtin.os.tag) {
src/link/Elf/relocatable.zig+32-33
......@@ -1,3 +1,23 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const elf = std.elf;
4const math = std.math;
5const mem = std.mem;
6const Path = std.Build.Cache.Path;
7const log = std.log.scoped(.link);
8const state_log = std.log.scoped(.link_state);
9
10const build_options = @import("build_options");
11
12const eh_frame = @import("eh_frame.zig");
13const link = @import("../../link.zig");
14const Archive = @import("Archive.zig");
15const Compilation = @import("../../Compilation.zig");
16const Elf = @import("../Elf.zig");
17const File = @import("file.zig").File;
18const Object = @import("Object.zig");
19const Symbol = @import("Symbol.zig");
20
121pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
222 const gpa = comp.gpa;
323 const io = comp.io;
......@@ -127,7 +147,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
127147 assert(writer.buffered().len == total_size);
128148
129149 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);
131151
132152 if (diags.hasErrors()) return error.LinkFailure;
133153}
......@@ -331,13 +351,7 @@ fn allocateAllocSections(elf_file: *Elf) !void {
331351
332352 if (shdr.sh_offset > 0) {
333353 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);
341355 }
342356
343357 shdr.sh_offset = new_offset;
......@@ -361,7 +375,9 @@ fn writeAtoms(elf_file: *Elf) !void {
361375}
362376
363377fn 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;
365381 const slice = elf_file.sections.slice();
366382
367383 const SortRelocs = struct {
......@@ -398,7 +414,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
398414 shdr.sh_offset + shdr.sh_size,
399415 });
400416
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);
402418 }
403419
404420 if (elf_file.section_indexes.eh_frame) |shndx| {
......@@ -418,7 +434,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
418434 shdr.sh_offset + sh_size,
419435 });
420436 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);
422438 }
423439 if (elf_file.section_indexes.eh_frame_rela) |shndx| {
424440 const shdr = slice.items(.shdr)[shndx];
......@@ -436,7 +452,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
436452 shdr.sh_offset,
437453 shdr.sh_offset + shdr.sh_size,
438454 });
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);
440456 }
441457
442458 try writeGroups(elf_file);
......@@ -445,7 +461,9 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
445461}
446462
447463fn 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;
449467 for (elf_file.group_sections.items) |cgs| {
450468 const shdr = elf_file.sections.items(.shdr)[cgs.shndx];
451469 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
......@@ -458,25 +476,6 @@ fn writeGroups(elf_file: *Elf) !void {
458476 shdr.sh_offset,
459477 shdr.sh_offset + shdr.sh_size,
460478 });
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);
462480 }
463481}
464
465const assert = std.debug.assert;
466const build_options = @import("build_options");
467const eh_frame = @import("eh_frame.zig");
468const elf = std.elf;
469const link = @import("../../link.zig");
470const log = std.log.scoped(.link);
471const math = std.math;
472const mem = std.mem;
473const state_log = std.log.scoped(.link_state);
474const Path = std.Build.Cache.Path;
475const std = @import("std");
476
477const Archive = @import("Archive.zig");
478const Compilation = @import("../../Compilation.zig");
479const Elf = @import("../Elf.zig");
480const File = @import("file.zig").File;
481const Object = @import("Object.zig");
482const Symbol = @import("Symbol.zig");
src/link/Lld.zig+14-8
......@@ -406,6 +406,7 @@ fn coffLink(lld: *Lld, arena: Allocator) !void {
406406 the_object_path.sub_path,
407407 directory.handle,
408408 base.emit.sub_path,
409 io,
409410 .{},
410411 );
411412 } else {
......@@ -756,6 +757,7 @@ fn findLib(arena: Allocator, io: Io, name: []const u8, lib_directories: []const
756757fn elfLink(lld: *Lld, arena: Allocator) !void {
757758 const comp = lld.base.comp;
758759 const gpa = comp.gpa;
760 const io = comp.io;
759761 const diags = &comp.link_diags;
760762 const base = &lld.base;
761763 const elf = &lld.ofmt.elf;
......@@ -822,6 +824,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
822824 the_object_path.sub_path,
823825 directory.handle,
824826 base.emit.sub_path,
827 io,
825828 .{},
826829 );
827830 } else {
......@@ -1336,6 +1339,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {
13361339 const wasm = &lld.ofmt.wasm;
13371340
13381341 const gpa = comp.gpa;
1342 const io = comp.io;
13391343
13401344 const directory = base.emit.root_dir; // Just an alias to make it shorter to type.
13411345 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 {
13781382 the_object_path.sub_path,
13791383 directory.handle,
13801384 base.emit.sub_path,
1385 io,
13811386 .{},
13821387 );
13831388 } else {
......@@ -1571,7 +1576,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {
15711576 comp.config.output_mode == .Exe)
15721577 {
15731578 // 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|
15751580 return diags.fail("{s}: failed to enable executable permissions: {t}", .{ full_out_path, err });
15761581 }
15771582 }
......@@ -1579,6 +1584,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {
15791584
15801585fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !void {
15811586 const io = comp.io;
1587 const gpa = comp.gpa;
15821588
15831589 if (comp.verbose_link) {
15841590 // 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
15961602 }
15971603
15981604 var stderr: []u8 = &.{};
1599 defer comp.gpa.free(stderr);
1605 defer gpa.free(stderr);
16001606
16011607 var child = std.process.Child.init(argv, arena);
16021608 const term = (if (comp.clang_passthrough_mode) term: {
......@@ -1612,8 +1618,8 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
16121618
16131619 child.spawn(io) catch |err| break :term err;
16141620 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);
16171623 }) catch |first_err| term: {
16181624 const err = switch (first_err) {
16191625 error.NameTooLong => err: {
......@@ -1622,8 +1628,8 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
16221628 const rsp_path = "tmp" ++ s ++ std.fmt.hex(rand_int) ++ ".rsp";
16231629
16241630 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 });
16271633 {
16281634 defer rsp_file.close(io);
16291635 var rsp_file_buffer: [1024]u8 = undefined;
......@@ -1662,8 +1668,8 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
16621668
16631669 rsp_child.spawn(io) catch |err| break :err err;
16641670 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;
16671673 }
16681674 },
16691675 else => first_err,
src/link/MachO.zig+64-41
......@@ -347,7 +347,8 @@ pub fn flush(
347347
348348 const comp = self.base.comp;
349349 const gpa = comp.gpa;
350 const diags = &self.base.comp.link_diags;
350 const io = comp.io;
351 const diags = &comp.link_diags;
351352
352353 const sub_prog_node = prog_node.start("MachO Flush", 0);
353354 defer sub_prog_node.end();
......@@ -380,26 +381,26 @@ pub fn flush(
380381 // in this set.
381382 try positionals.ensureUnusedCapacity(comp.c_object_table.keys().len);
382383 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));
384385 }
385386
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));
387388
388389 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));
390391 }
391392
392393 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));
394395 }
395396
396397 if (comp.ubsan_rt_lib) |crt_file| {
397398 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|
399400 diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)});
400401 } else if (comp.ubsan_rt_obj) |crt_file| {
401402 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|
403404 diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)});
404405 }
405406
......@@ -434,7 +435,7 @@ pub fn flush(
434435 if (comp.config.link_libc and is_exe_or_dyn_lib) {
435436 if (comp.zigc_static_lib) |zigc| {
436437 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|
438439 diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)});
439440 }
440441 }
......@@ -457,12 +458,12 @@ pub fn flush(
457458 for (system_libs.items) |lib| {
458459 switch (Compilation.classifyFileExt(lib.path.sub_path)) {
459460 .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);
461462 self.classifyInputFile(dso_input) catch |err|
462463 diags.addParseError(lib.path, "failed to parse input file: {s}", .{@errorName(err)});
463464 },
464465 .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);
466467 self.classifyInputFile(archive_input) catch |err|
467468 diags.addParseError(lib.path, "failed to parse input file: {s}", .{@errorName(err)});
468469 },
......@@ -473,11 +474,11 @@ pub fn flush(
473474 // Finally, link against compiler_rt.
474475 if (comp.compiler_rt_lib) |crt_file| {
475476 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|
477478 diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)});
478479 } else if (comp.compiler_rt_obj) |crt_file| {
479480 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|
481482 diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(err)});
482483 }
483484
......@@ -568,7 +569,7 @@ pub fn flush(
568569 self.writeLinkeditSectionsToFile() catch |err| switch (err) {
569570 error.OutOfMemory => return error.OutOfMemory,
570571 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}),
572573 };
573574
574575 var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: {
......@@ -579,8 +580,8 @@ pub fn flush(
579580 // where the code signature goes into.
580581 var codesig = CodeSignature.init(self.getPageSize());
581582 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 });
584585 try self.writeCodeSignaturePadding(&codesig);
585586 break :blk codesig;
586587 } else null;
......@@ -866,6 +867,9 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {
866867 const tracy = trace(@src());
867868 defer tracy.end();
868869
870 const comp = self.base.comp;
871 const io = comp.io;
872
869873 const path, const file = input.pathAndFile().?;
870874 // TODO don't classify now, it's too late. The input file has already been classified
871875 log.debug("classifying input file {f}", .{path});
......@@ -876,7 +880,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {
876880 const fat_arch: ?fat.Arch = try self.parseFatFile(file, path);
877881 const offset = if (fat_arch) |fa| fa.offset else 0;
878882
879 if (readMachHeader(file, offset) catch null) |h| blk: {
883 if (readMachHeader(io, file, offset) catch null) |h| blk: {
880884 if (h.magic != macho.MH_MAGIC_64) break :blk;
881885 switch (h.filetype) {
882886 macho.MH_OBJECT => try self.addObject(path, fh, offset),
......@@ -885,7 +889,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {
885889 }
886890 return;
887891 }
888 if (readArMagic(file, offset, &buffer) catch null) |ar_magic| blk: {
892 if (readArMagic(io, file, offset, &buffer) catch null) |ar_magic| blk: {
889893 if (!mem.eql(u8, ar_magic, Archive.ARMAG)) break :blk;
890894 try self.addArchive(input.archive, fh, fat_arch);
891895 return;
......@@ -894,11 +898,13 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {
894898}
895899
896900fn 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;
899905 if (fat_h.magic != macho.FAT_MAGIC and fat_h.magic != macho.FAT_MAGIC_64) return null;
900906 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);
902908 const cpu_arch = self.getTarget().cpu.arch;
903909 for (fat_archs) |arch| {
904910 if (arch.tag == cpu_arch) return arch;
......@@ -906,16 +912,16 @@ fn parseFatFile(self: *MachO, file: Io.File, path: Path) !?fat.Arch {
906912 return diags.failParse(path, "missing arch in universal file: expected {s}", .{@tagName(cpu_arch)});
907913}
908914
909pub fn readMachHeader(file: Io.File, offset: usize) !macho.mach_header_64 {
915pub fn readMachHeader(io: Io, file: Io.File, offset: usize) !macho.mach_header_64 {
910916 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);
912918 if (nread != buffer.len) return error.InputOutput;
913919 const hdr = @as(*align(1) const macho.mach_header_64, @ptrCast(&buffer)).*;
914920 return hdr;
915921}
916922
917pub fn readArMagic(file: Io.File, offset: usize, buffer: *[Archive.SARMAG]u8) ![]const u8 {
918 const nread = try file.preadAll(buffer, offset);
923pub fn readArMagic(io: Io, file: Io.File, offset: usize, buffer: *[Archive.SARMAG]u8) ![]const u8 {
924 const nread = try file.readPositionalAll(io, buffer, offset);
919925 if (nread != buffer.len) return error.InputOutput;
920926 return buffer[0..Archive.SARMAG];
921927}
......@@ -1212,7 +1218,8 @@ fn parseDependentDylibs(self: *MachO) !void {
12121218 const rel_path = try fs.path.join(arena, &.{ prefix, path });
12131219 try checked_paths.append(rel_path);
12141220 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];
12161223 break :full_path try arena.dupe(u8, full_path);
12171224 }
12181225 } else if (eatPrefix(id.name, "@loader_path/")) |_| {
......@@ -1225,8 +1232,9 @@ fn parseDependentDylibs(self: *MachO) !void {
12251232
12261233 try checked_paths.append(try arena.dupe(u8, id.name));
12271234 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]);
12301238 } else |_| {
12311239 try self.reportMissingDependencyError(
12321240 self.getFile(dylib_index).?.dylib.getUmbrella(self).index,
......@@ -1248,7 +1256,7 @@ fn parseDependentDylibs(self: *MachO) !void {
12481256 const fat_arch = try self.parseFatFile(file, lib.path);
12491257 const offset = if (fat_arch) |fa| fa.offset else 0;
12501258 const file_index = file_index: {
1251 if (readMachHeader(file, offset) catch null) |h| blk: {
1259 if (readMachHeader(io, file, offset) catch null) |h| blk: {
12521260 if (h.magic != macho.MH_MAGIC_64) break :blk;
12531261 switch (h.filetype) {
12541262 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)
32443252}
32453253
32463254pub 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);
32503256}
32513257
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.
32533259/// This is so that we guarantee zeroed out regions for mapping of zerofill sections by the loader.
32543260fn 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;
32573269 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 };
32623285}
32633286
32643287const InitMetadataOptions = struct {
......@@ -5355,10 +5378,10 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
53555378
53565379pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void {
53575380 const comp = macho_file.base.comp;
5381 const io = comp.io;
53585382 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});
53625385}
53635386
53645387pub 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
2424
2525 var hdr_buffer: [@sizeOf(ar_hdr)]u8 = undefined;
2626 {
27 const amt = try handle.preadAll(&hdr_buffer, pos);
27 const amt = try handle.readPositionalAll(io, &hdr_buffer, pos);
2828 if (amt != @sizeOf(ar_hdr)) return error.InputOutput;
2929 }
3030 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
4242 if (try hdr.nameLength()) |len| {
4343 hdr_size -= len;
4444 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);
4646 if (amt != len) return error.InputOutput;
4747 pos += len;
4848 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(
135135 const new_offset = try self.findFreeSpace(needed_size, 1);
136136
137137 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,
142139 });
143140
144141 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);
152144 }
153145
154146 sect.offset = @intCast(new_offset);
......@@ -204,6 +196,7 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) !u64
204196}
205197
206198pub fn flush(self: *DebugSymbols, macho_file: *MachO) !void {
199 const io = self.io;
207200 const zo = macho_file.getZigObject().?;
208201 for (self.relocs.items) |*reloc| {
209202 const sym = zo.symbols.items[reloc.target];
......@@ -215,12 +208,9 @@ pub fn flush(self: *DebugSymbols, macho_file: *MachO) !void {
215208 const sect = &self.sections.items[self.debug_info_section_index.?];
216209 const file_offset = sect.offset + reloc.offset;
217210 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,
222212 });
223 try self.file.?.pwriteAll(mem.asBytes(&addr), file_offset);
213 try self.file.?.writePositionalAll(io, mem.asBytes(&addr), file_offset);
224214 }
225215
226216 self.finalizeDwarfSegment(macho_file);
......@@ -294,6 +284,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
294284}
295285
296286fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } {
287 const io = self.io;
297288 const gpa = self.allocator;
298289 const needed_size = load_commands.calcLoadCommandsSizeDsym(macho_file, self);
299290 const buffer = try gpa.alloc(u8, needed_size);
......@@ -345,12 +336,13 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
345336
346337 assert(writer.end == needed_size);
347338
348 try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
339 try self.file.?.writePositionalAll(io, buffer, @sizeOf(macho.mach_header_64));
349340
350341 return .{ ncmds, buffer.len };
351342}
352343
353344fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
345 const io = self.io;
354346 var header: macho.mach_header_64 = .{};
355347 header.filetype = macho.MH_DSYM;
356348
......@@ -371,7 +363,7 @@ fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds
371363
372364 log.debug("writing Mach-O header {}", .{header});
373365
374 try self.file.?.pwriteAll(mem.asBytes(&header), 0);
366 try self.file.?.writePositionalAll(io, mem.asBytes(&header), 0);
375367}
376368
377369fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
......@@ -406,6 +398,8 @@ fn writeLinkeditSegmentData(self: *DebugSymbols, macho_file: *MachO) !void {
406398pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 {
407399 const tracy = trace(@src());
408400 defer tracy.end();
401
402 const io = self.io;
409403 const gpa = self.allocator;
410404 const cmd = &self.symtab_cmd;
411405 cmd.nsyms = macho_file.symtab_cmd.nsyms;
......@@ -429,15 +423,16 @@ pub fn writeSymtab(self: *DebugSymbols, off: u32, macho_file: *MachO) !u32 {
429423 internal.writeSymtab(macho_file, self);
430424 }
431425
432 try self.file.?.pwriteAll(@ptrCast(self.symtab.items), cmd.symoff);
426 try self.file.?.writePositionalAll(io, @ptrCast(self.symtab.items), cmd.symoff);
433427
434428 return off + cmd.nsyms * @sizeOf(macho.nlist_64);
435429}
436430
437431pub fn writeStrtab(self: *DebugSymbols, off: u32) !u32 {
432 const io = self.io;
438433 const cmd = &self.symtab_cmd;
439434 cmd.stroff = off;
440 try self.file.?.pwriteAll(self.strtab.items, cmd.stroff);
435 try self.file.?.writePositionalAll(io, self.strtab.items, cmd.stroff);
441436 return off + cmd.strsize;
442437}
443438
src/link/MachO/Dylib.zig+12-8
......@@ -57,7 +57,9 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
5757 const tracy = trace(@src());
5858 defer tracy.end();
5959
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;
6163 const file = macho_file.getFileHandle(self.file_handle);
6264 const offset = self.offset;
6365
......@@ -65,7 +67,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
6567
6668 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
6769 {
68 const amt = try file.preadAll(&header_buffer, offset);
70 const amt = try file.readPositionalAll(io, &header_buffer, offset);
6971 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
7072 }
7173 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 {
8688 const lc_buffer = try gpa.alloc(u8, header.sizeofcmds);
8789 defer gpa.free(lc_buffer);
8890 {
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));
9092 if (amt != lc_buffer.len) return error.InputOutput;
9193 }
9294
......@@ -103,7 +105,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
103105 const dyld_cmd = cmd.cast(macho.dyld_info_command).?;
104106 const data = try gpa.alloc(u8, dyld_cmd.export_size);
105107 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);
107109 if (amt != data.len) return error.InputOutput;
108110 try self.parseTrie(data, macho_file);
109111 },
......@@ -111,7 +113,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
111113 const ld_cmd = cmd.cast(macho.linkedit_data_command).?;
112114 const data = try gpa.alloc(u8, ld_cmd.datasize);
113115 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);
115117 if (amt != data.len) return error.InputOutput;
116118 try self.parseTrie(data, macho_file);
117119 },
......@@ -238,13 +240,15 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
238240 const tracy = trace(@src());
239241 defer tracy.end();
240242
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;
242246
243247 log.debug("parsing dylib from stub: {f}", .{self.path});
244248
245249 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});
248252 return error.MalformedTbd;
249253 };
250254 defer lib_stub.deinit();
src/link/MachO/Object.zig+88-61
......@@ -1,3 +1,30 @@
1const Object = @This();
2
3const trace = @import("../../tracy.zig").trace;
4const Archive = @import("Archive.zig");
5const Atom = @import("Atom.zig");
6const Dwarf = @import("Dwarf.zig");
7const File = @import("file.zig").File;
8const MachO = @import("../MachO.zig");
9const Relocation = @import("Relocation.zig");
10const Symbol = @import("Symbol.zig");
11const UnwindInfo = @import("UnwindInfo.zig");
12
13const std = @import("std");
14const Io = std.Io;
15const Writer = std.Io.Writer;
16const assert = std.debug.assert;
17const log = std.log.scoped(.link);
18const macho = std.macho;
19const LoadCommandIterator = macho.LoadCommandIterator;
20const math = std.math;
21const mem = std.mem;
22const Allocator = std.mem.Allocator;
23
24const eh_frame = @import("eh_frame.zig");
25const Cie = eh_frame.Cie;
26const Fde = eh_frame.Fde;
27
128/// Non-zero for fat object files or archives
229offset: u64,
330/// 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 {
75102
76103 log.debug("parsing {f}", .{self.fmtPath()});
77104
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;
79108 const handle = macho_file.getFileHandle(self.file_handle);
80109 const cpu_arch = macho_file.getTarget().cpu.arch;
81110
......@@ -84,7 +113,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
84113
85114 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
86115 {
87 const amt = try handle.preadAll(&header_buffer, self.offset);
116 const amt = try handle.readPositionalAll(io, &header_buffer, self.offset);
88117 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
89118 }
90119 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 {
105134 const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);
106135 defer gpa.free(lc_buffer);
107136 {
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));
109138 if (amt != self.header.?.sizeofcmds) return error.InputOutput;
110139 }
111140
......@@ -129,14 +158,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
129158 const cmd = lc.cast(macho.symtab_command).?;
130159 try self.strtab.resize(gpa, cmd.strsize);
131160 {
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);
133162 if (amt != self.strtab.items.len) return error.InputOutput;
134163 }
135164
136165 const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));
137166 defer gpa.free(symtab_buffer);
138167 {
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);
140169 if (amt != symtab_buffer.len) return error.InputOutput;
141170 }
142171 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 {
154183 const buffer = try gpa.alloc(u8, cmd.datasize);
155184 defer gpa.free(buffer);
156185 {
157 const amt = try handle.preadAll(buffer, self.offset + cmd.dataoff);
186 const amt = try handle.readPositionalAll(io, buffer, self.offset + cmd.dataoff);
158187 if (amt != buffer.len) return error.InputOutput;
159188 }
160189 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
440469 const tracy = trace(@src());
441470 defer tracy.end();
442471
472 const comp = macho_file.base.comp;
473 const io = comp.io;
443474 const slice = self.sections.slice();
444475
445476 for (slice.items(.header), 0..) |sect, n_sect| {
446477 if (!isCstringLiteral(sect)) continue;
447478
448 const data = try self.readSectionData(allocator, file, @intCast(n_sect));
479 const data = try self.readSectionData(allocator, io, file, @intCast(n_sect));
449480 defer allocator.free(data);
450481
451482 var count: u32 = 0;
......@@ -628,7 +659,9 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
628659 const tracy = trace(@src());
629660 defer tracy.end();
630661
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;
632665 const file = macho_file.getFileHandle(self.file_handle);
633666
634667 var buffer = std.array_list.Managed(u8).init(gpa);
......@@ -647,7 +680,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
647680 const slice = self.sections.slice();
648681 for (slice.items(.header), slice.items(.subsections), 0..) |header, subs, n_sect| {
649682 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));
651684 defer gpa.free(data);
652685
653686 for (subs.items) |sub| {
......@@ -682,7 +715,7 @@ pub fn resolveLiterals(self: *Object, lp: *MachO.LiteralPool, macho_file: *MachO
682715 buffer.resize(target_size) catch unreachable;
683716 const gop = try sections_data.getOrPut(target.n_sect);
684717 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));
686719 }
687720 const data = gop.value_ptr.*;
688721 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
10371070 const sect = slice.items(.header)[sect_id];
10381071 const relocs = slice.items(.relocs)[sect_id];
10391072
1073 const comp = macho_file.base.comp;
1074 const io = comp.io;
10401075 const size = try macho_file.cast(usize, sect.size);
10411076 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);
10431078 if (amt != self.eh_frame_data.items.len) return error.InputOutput;
10441079
10451080 // 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
11381173 }
11391174 };
11401175
1176 const comp = macho_file.base.comp;
1177 const io = comp.io;
11411178 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);
11431180 defer allocator.free(data);
11441181
11451182 const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry));
......@@ -1348,7 +1385,9 @@ fn parseDebugInfo(self: *Object, macho_file: *MachO) !void {
13481385 const tracy = trace(@src());
13491386 defer tracy.end();
13501387
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;
13521391 const file = macho_file.getFileHandle(self.file_handle);
13531392
13541393 var dwarf: Dwarf = .{};
......@@ -1358,18 +1397,18 @@ fn parseDebugInfo(self: *Object, macho_file: *MachO) !void {
13581397 const n_sect: u8 = @intCast(index);
13591398 if (sect.attrs() & macho.S_ATTR_DEBUG == 0) continue;
13601399 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);
13621401 }
13631402 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);
13651404 }
13661405 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);
13681407 }
13691408 // __debug_str_offs[ets] section is a new addition in DWARFv5 and is generally
13701409 // required in order to correctly parse strings.
13711410 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);
13731412 }
13741413 }
13751414
......@@ -1611,12 +1650,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void {
16111650 const tracy = trace(@src());
16121651 defer tracy.end();
16131652
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;
16151656 const handle = macho_file.getFileHandle(self.file_handle);
16161657
16171658 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
16181659 {
1619 const amt = try handle.preadAll(&header_buffer, self.offset);
1660 const amt = try handle.readPositionalAll(io, &header_buffer, self.offset);
16201661 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
16211662 }
16221663 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 {
16371678 const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);
16381679 defer gpa.free(lc_buffer);
16391680 {
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));
16411682 if (amt != self.header.?.sizeofcmds) return error.InputOutput;
16421683 }
16431684
......@@ -1647,14 +1688,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void {
16471688 const cmd = lc.cast(macho.symtab_command).?;
16481689 try self.strtab.resize(gpa, cmd.strsize);
16491690 {
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);
16511692 if (amt != self.strtab.items.len) return error.InputOutput;
16521693 }
16531694
16541695 const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));
16551696 defer gpa.free(symtab_buffer);
16561697 {
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);
16581699 if (amt != symtab_buffer.len) return error.InputOutput;
16591700 }
16601701 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 {
16971738 };
16981739}
16991740
1700pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
1741pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: *Writer) !void {
17011742 // Header
17021743 const size = try macho_file.cast(usize, self.output_ar_state.size);
17031744 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
17051746 // Data
17061747 const file = macho_file.getFileHandle(self.file_handle);
17071748 // 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;
17091752 const data = try gpa.alloc(u8, size);
17101753 defer gpa.free(data);
1711 const amt = try file.preadAll(data, self.offset);
1754 const amt = try file.readPositionalAll(io, data, self.offset);
17121755 if (amt != size) return error.InputOutput;
17131756 try writer.writeAll(data);
17141757}
......@@ -1813,7 +1856,9 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void {
18131856 const tracy = trace(@src());
18141857 defer tracy.end();
18151858
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;
18171862 const headers = self.sections.items(.header);
18181863 const sections_data = try gpa.alloc([]const u8, headers.len);
18191864 defer {
......@@ -1829,7 +1874,7 @@ pub fn writeAtoms(self: *Object, macho_file: *MachO) !void {
18291874 if (header.isZerofill()) continue;
18301875 const size = try macho_file.cast(usize, header.size);
18311876 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);
18331878 if (amt != data.len) return error.InputOutput;
18341879 sections_data[n_sect] = data;
18351880 }
......@@ -1852,7 +1897,9 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
18521897 const tracy = trace(@src());
18531898 defer tracy.end();
18541899
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;
18561903 const headers = self.sections.items(.header);
18571904 const sections_data = try gpa.alloc([]const u8, headers.len);
18581905 defer {
......@@ -1868,7 +1915,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
18681915 if (header.isZerofill()) continue;
18691916 const size = try macho_file.cast(usize, header.size);
18701917 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);
18721919 if (amt != data.len) return error.InputOutput;
18731920 sections_data[n_sect] = data;
18741921 }
......@@ -2484,11 +2531,11 @@ pub fn getUnwindRecord(self: *Object, index: UnwindInfo.Record.Index) *UnwindInf
24842531}
24852532
24862533/// Caller owns the memory.
2487pub fn readSectionData(self: Object, allocator: Allocator, file: File.Handle, n_sect: u8) ![]u8 {
2534pub fn readSectionData(self: Object, allocator: Allocator, io: Io, file: File.Handle, n_sect: u8) ![]u8 {
24882535 const header = self.sections.items(.header)[n_sect];
24892536 const size = math.cast(usize, header.size) orelse return error.Overflow;
24902537 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);
24922539 errdefer allocator.free(data);
24932540 if (amt != data.len) return error.InputOutput;
24942541 return data;
......@@ -2712,15 +2759,17 @@ const x86_64 = struct {
27122759 handle: File.Handle,
27132760 macho_file: *MachO,
27142761 ) !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;
27162765
27172766 const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
27182767 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);
27202769 if (amt != relocs_buffer.len) return error.InputOutput;
27212770 const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
27222771
2723 const code = try self.readSectionData(gpa, handle, n_sect);
2772 const code = try self.readSectionData(gpa, io, handle, n_sect);
27242773 defer gpa.free(code);
27252774
27262775 try out.ensureTotalCapacityPrecise(gpa, relocs.len);
......@@ -2879,15 +2928,17 @@ const aarch64 = struct {
28792928 handle: File.Handle,
28802929 macho_file: *MachO,
28812930 ) !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;
28832934
28842935 const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
28852936 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);
28872938 if (amt != relocs_buffer.len) return error.InputOutput;
28882939 const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
28892940
2890 const code = try self.readSectionData(gpa, handle, n_sect);
2941 const code = try self.readSectionData(gpa, io, handle, n_sect);
28912942 defer gpa.free(code);
28922943
28932944 try out.ensureTotalCapacityPrecise(gpa, relocs.len);
......@@ -3063,27 +3114,3 @@ const aarch64 = struct {
30633114 }
30643115 }
30653116};
3066
3067const std = @import("std");
3068const assert = std.debug.assert;
3069const log = std.log.scoped(.link);
3070const macho = std.macho;
3071const math = std.math;
3072const mem = std.mem;
3073const Allocator = std.mem.Allocator;
3074const Writer = std.Io.Writer;
3075
3076const eh_frame = @import("eh_frame.zig");
3077const trace = @import("../../tracy.zig").trace;
3078const Archive = @import("Archive.zig");
3079const Atom = @import("Atom.zig");
3080const Cie = eh_frame.Cie;
3081const Dwarf = @import("Dwarf.zig");
3082const Fde = eh_frame.Fde;
3083const File = @import("file.zig").File;
3084const LoadCommandIterator = macho.LoadCommandIterator;
3085const MachO = @import("../MachO.zig");
3086const Object = @This();
3087const Relocation = @import("Relocation.zig");
3088const Symbol = @import("Symbol.zig");
3089const 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
171171 const isec = atom.getInputSection(macho_file);
172172 assert(!isec.isZerofill());
173173
174 const comp = macho_file.base.comp;
175 const io = comp.io;
176
174177 switch (isec.type()) {
175178 macho.S_THREAD_LOCAL_REGULAR => {
176179 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
182185 else => {
183186 const sect = macho_file.sections.items(.header)[atom.out_n_sect];
184187 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);
186189 if (amt != buffer.len) return error.InputOutput;
187190 },
188191 }
......@@ -290,12 +293,14 @@ pub fn dedupLiterals(self: *ZigObject, lp: MachO.LiteralPool, macho_file: *MachO
290293/// We need this so that we can write to an archive.
291294/// TODO implement writing ZigObject data directly to a buffer instead.
292295pub 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;
294300 // Size of the output object file is always the offset + size of the strtab
295301 const size = macho_file.symtab_cmd.stroff + macho_file.symtab_cmd.strsize;
296 const gpa = macho_file.base.comp.gpa;
297302 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|
299304 return diags.fail("failed to read output file: {s}", .{@errorName(err)});
300305 if (amt != size)
301306 return diags.fail("unexpected EOF reading from output file", .{});
......@@ -945,6 +950,8 @@ fn updateNavCode(
945950) link.File.UpdateNavError!void {
946951 const zcu = pt.zcu;
947952 const gpa = zcu.gpa;
953 const comp = zcu.comp;
954 const io = comp.io;
948955 const ip = &zcu.intern_pool;
949956 const nav = ip.getNav(nav_index);
950957
......@@ -1012,8 +1019,8 @@ fn updateNavCode(
10121019
10131020 if (!sect.isZerofill()) {
10141021 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});
10171024 }
10181025}
10191026
......@@ -1493,7 +1500,7 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, macho_file: *MachO) !void {
14931500 .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf),
14941501 else => @panic("TODO implement write trampoline for this CPU arch"),
14951502 };
1496 try macho_file.base.file.?.pwriteAll(out, fileoff);
1503 return macho_file.pwriteAll(out, fileoff);
14971504}
14981505
14991506pub fn getOrCreateMetadataForNav(
src/link/MachO/fat.zig+6-6
......@@ -10,13 +10,13 @@ const mem = std.mem;
1010
1111const MachO = @import("../MachO.zig");
1212
13pub fn readFatHeader(file: Io.File) !macho.fat_header {
14 return readFatHeaderGeneric(macho.fat_header, file, 0);
13pub fn readFatHeader(io: Io, file: Io.File) !macho.fat_header {
14 return readFatHeaderGeneric(io, macho.fat_header, file, 0);
1515}
1616
17fn readFatHeaderGeneric(comptime Hdr: type, file: Io.File, offset: usize) !Hdr {
17fn readFatHeaderGeneric(io: Io, comptime Hdr: type, file: Io.File, offset: usize) !Hdr {
1818 var buffer: [@sizeOf(Hdr)]u8 = undefined;
19 const nread = try file.preadAll(&buffer, offset);
19 const nread = try file.readPositionalAll(io, &buffer, offset);
2020 if (nread != buffer.len) return error.InputOutput;
2121 var hdr = @as(*align(1) const Hdr, @ptrCast(&buffer)).*;
2222 mem.byteSwapAllFields(Hdr, &hdr);
......@@ -29,12 +29,12 @@ pub const Arch = struct {
2929 size: u32,
3030};
3131
32pub fn parseArchs(file: Io.File, fat_header: macho.fat_header, out: *[2]Arch) ![]const Arch {
32pub fn parseArchs(io: Io, file: Io.File, fat_header: macho.fat_header, out: *[2]Arch) ![]const Arch {
3333 var count: usize = 0;
3434 var fat_arch_index: u32 = 0;
3535 while (fat_arch_index < fat_header.nfat_arch and count < out.len) : (fat_arch_index += 1) {
3636 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);
3838 // If we come across an architecture that we do not know how to handle, that's
3939 // fine because we can keep looking for one that might match.
4040 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 {
99 const hash_size = Hasher.digest_length;
1010
1111 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 {
1313 chunk_size: u64 = 0x4000,
1414 max_file_size: ?u64 = null,
1515 }) !void {
......@@ -22,11 +22,11 @@ pub fn ParallelHasher(comptime Hasher: type) type {
2222 };
2323 const chunk_size = std.math.cast(usize, opts.chunk_size) orelse return error.Overflow;
2424
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);
2727
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);
3030
3131 {
3232 var group: Io.Group = .init;
......@@ -38,7 +38,8 @@ pub fn ParallelHasher(comptime Hasher: type) type {
3838 file_size - fstart
3939 else
4040 chunk_size;
41 group.async(worker, .{
41 group.async(io, worker, .{
42 io,
4243 file,
4344 fstart,
4445 buffer[fstart..][0..fsize],
......@@ -53,16 +54,15 @@ pub fn ParallelHasher(comptime Hasher: type) type {
5354 }
5455
5556 fn worker(
57 io: Io,
5658 file: Io.File,
5759 fstart: usize,
5860 buffer: []u8,
5961 out: *[hash_size]u8,
6062 err: *Io.File.ReadPositionalError!usize,
6163 ) void {
62 err.* = file.readPositionalAll(buffer, fstart);
64 err.* = file.readPositionalAll(io, buffer, fstart);
6365 Hasher.hash(buffer, out, .{});
6466 }
65
66 const Self = @This();
6767 };
6868}
src/link/MachO/relocatable.zig+9-11
......@@ -10,10 +10,10 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
1010 positionals.appendSliceAssumeCapacity(comp.link_inputs);
1111
1212 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));
1414 }
1515
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));
1717
1818 if (macho_file.getZigObject() == null and positionals.items.len == 1) {
1919 // 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
2424 return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) });
2525 const stat = in_file.stat(io) catch |err|
2626 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 });
3129 return;
3230 }
3331
......@@ -90,17 +88,17 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
9088 positionals.appendSliceAssumeCapacity(comp.link_inputs);
9189
9290 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));
9492 }
9593
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));
9795
9896 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));
10098 }
10199
102100 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));
104102 }
105103
106104 for (positionals.items) |link_input| {
......@@ -231,7 +229,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
231229
232230 assert(writer.end == total_size);
233231
234 try macho_file.setLength(io, total_size);
232 try macho_file.setLength(total_size);
235233 try macho_file.pwriteAll(writer.buffered(), 0);
236234
237235 if (diags.hasErrors()) return error.LinkFailure;
src/link/SpirV.zig+3-2
......@@ -246,6 +246,7 @@ pub fn flush(
246246 const comp = linker.base.comp;
247247 const diags = &comp.link_diags;
248248 const gpa = comp.gpa;
249 const io = comp.io;
249250
250251 // We need to export the list of error names somewhere so that we can pretty-print them in the
251252 // 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(
287288 };
288289
289290 // 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});
292293}
293294
294295fn linkModule(arena: Allocator, module: []Word, progress: std.Progress.Node) ![]Word {
src/link/Wasm.zig+4-2
......@@ -3016,8 +3016,10 @@ pub fn createEmpty(
30163016}
30173017
30183018fn 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| {
30213023 switch (diags.failParse(path, "failed to open object: {t}", .{err})) {
30223024 error.LinkFailure => return,
30233025 }
src/link/Wasm/Flush.zig+2-1
......@@ -108,6 +108,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {
108108
109109pub fn finish(f: *Flush, wasm: *Wasm) !void {
110110 const comp = wasm.base.comp;
111 const io = comp.io;
111112 const shared_memory = comp.config.shared_memory;
112113 const diags = &comp.link_diags;
113114 const gpa = comp.gpa;
......@@ -1067,7 +1068,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
10671068 }
10681069
10691070 // 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, &.{});
10711072 file_writer.interface.writeAll(binary_bytes.items) catch |err| switch (err) {
10721073 error.WriteFailed => return file_writer.err.?,
10731074 };
src/link/tapi.zig+2-2
......@@ -130,7 +130,7 @@ pub const Tbd = union(enum) {
130130pub const TapiError = error{
131131 NotLibStub,
132132 InputOutput,
133} || yaml.YamlError || Io.File.PReadError;
133} || yaml.YamlError || Io.File.ReadPositionalError;
134134
135135pub const LibStub = struct {
136136 /// Underlying memory for stub's contents.
......@@ -146,7 +146,7 @@ pub const LibStub = struct {
146146 };
147147 const source = try allocator.alloc(u8, filesize);
148148 defer allocator.free(source);
149 const amt = try file.preadAll(source, 0);
149 const amt = try file.readPositionalAll(io, source, 0);
150150 if (amt != filesize) return error.InputOutput;
151151
152152 var lib_stub = LibStub{
src/main.zig+1-1
......@@ -3677,7 +3677,7 @@ fn buildOutputType(
36773677 }
36783678
36793679 {
3680 const root_prog_node = std.Progress.start(.{
3680 const root_prog_node = std.Progress.start(io, .{
36813681 .disable_printing = (color == .off),
36823682 });
36833683 defer root_prog_node.end();