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