authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-16 19:32:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-28 18:30:57-07:00
logcc931660eb3e5b7251944c727808aa36e72c1e52
treec6564aff1d2e77163cfce1cd8e599a187ce9274a
parent2dc6ddd7e8cfb83f5ffd57b8b40f33dde9de892d

link.MachO: update to not use GenericWriter


15 files changed, 236 insertions(+), 250 deletions(-)

lib/std/Io/Writer.zig+1
...@@ -2381,6 +2381,7 @@ pub fn fromArrayList(array_list: *ArrayList(u8)) Writer {...@@ -2381,6 +2381,7 @@ pub fn fromArrayList(array_list: *ArrayList(u8)) Writer {
2381 .vtable = &.{2381 .vtable = &.{
2382 .drain = fixedDrain,2382 .drain = fixedDrain,
2383 .flush = noopFlush,2383 .flush = noopFlush,
2384 .rebase = failingRebase,
2384 },2385 },
2385 .buffer = array_list.allocatedSlice(),2386 .buffer = array_list.allocatedSlice(),
2386 .end = array_list.items.len,2387 .end = array_list.items.len,
lib/std/macho.zig-2
...@@ -1883,10 +1883,8 @@ pub const GenericBlob = extern struct {...@@ -1883,10 +1883,8 @@ pub const GenericBlob = extern struct {
1883pub const data_in_code_entry = extern struct {1883pub const data_in_code_entry = extern struct {
1884 /// From mach_header to start of data range.1884 /// From mach_header to start of data range.
1885 offset: u32,1885 offset: u32,
1886
1887 /// Number of bytes in data range.1886 /// Number of bytes in data range.
1888 length: u16,1887 length: u16,
1889
1890 /// A DICE_KIND value.1888 /// A DICE_KIND value.
1891 kind: u16,1889 kind: u16,
1892};1890};
src/link/MachO.zig+65-65
...@@ -589,7 +589,7 @@ pub fn flush(...@@ -589,7 +589,7 @@ pub fn flush(
589 );589 );
590590
591 const ncmds, const sizeofcmds, const uuid_cmd_offset = self.writeLoadCommands() catch |err| switch (err) {591 const ncmds, const sizeofcmds, const uuid_cmd_offset = self.writeLoadCommands() catch |err| switch (err) {
592 error.NoSpaceLeft => unreachable,592 error.WriteFailed => unreachable,
593 error.OutOfMemory => return error.OutOfMemory,593 error.OutOfMemory => return error.OutOfMemory,
594 error.LinkFailure => return error.LinkFailure,594 error.LinkFailure => return error.LinkFailure,
595 };595 };
...@@ -1074,7 +1074,7 @@ fn accessLibPath(...@@ -1074,7 +1074,7 @@ fn accessLibPath(
10741074
1075 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1075 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1076 test_path.clearRetainingCapacity();1076 test_path.clearRetainingCapacity();
1077 try test_path.writer().print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });1077 try test_path.print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
1078 try checked_paths.append(try arena.dupe(u8, test_path.items));1078 try checked_paths.append(try arena.dupe(u8, test_path.items));
1079 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {1079 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
1080 error.FileNotFound => continue,1080 error.FileNotFound => continue,
...@@ -1097,7 +1097,7 @@ fn accessFrameworkPath(...@@ -1097,7 +1097,7 @@ fn accessFrameworkPath(
10971097
1098 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1098 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1099 test_path.clearRetainingCapacity();1099 test_path.clearRetainingCapacity();
1100 try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{1100 try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
1101 search_dir,1101 search_dir,
1102 name,1102 name,
1103 name,1103 name,
...@@ -1178,9 +1178,9 @@ fn parseDependentDylibs(self: *MachO) !void {...@@ -1178,9 +1178,9 @@ fn parseDependentDylibs(self: *MachO) !void {
1178 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1178 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1179 test_path.clearRetainingCapacity();1179 test_path.clearRetainingCapacity();
1180 if (self.base.comp.sysroot) |root| {1180 if (self.base.comp.sysroot) |root| {
1181 try test_path.writer().print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });1181 try test_path.print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
1182 } else {1182 } else {
1183 try test_path.writer().print("{s}{s}", .{ path, ext });1183 try test_path.print("{s}{s}", .{ path, ext });
1184 }1184 }
1185 try checked_paths.append(try arena.dupe(u8, test_path.items));1185 try checked_paths.append(try arena.dupe(u8, test_path.items));
1186 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {1186 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
...@@ -2528,8 +2528,8 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {...@@ -2528,8 +2528,8 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
2528 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {2528 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
2529 const off = try macho_file.cast(usize, th.value);2529 const off = try macho_file.cast(usize, th.value);
2530 const size = th.size();2530 const size = th.size();
2531 var stream = std.io.fixedBufferStream(buffer[off..][0..size]);2531 var stream: Writer = .fixed(buffer[off..][0..size]);
2532 try th.write(macho_file, stream.writer());2532 try th.write(macho_file, &stream);
2533 }2533 }
2534 }.doWork;2534 }.doWork;
2535 const out = self.sections.items(.out)[thunk.out_n_sect].items;2535 const out = self.sections.items(.out)[thunk.out_n_sect].items;
...@@ -2556,15 +2556,15 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {...@@ -2556,15 +2556,15 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {
25562556
2557 const doWork = struct {2557 const doWork = struct {
2558 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {2558 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {
2559 var stream = std.io.fixedBufferStream(buffer);2559 var stream: Writer = .fixed(buffer);
2560 switch (tag) {2560 switch (tag) {
2561 .eh_frame => eh_frame.write(macho_file, buffer),2561 .eh_frame => eh_frame.write(macho_file, buffer),
2562 .unwind_info => try macho_file.unwind_info.write(macho_file, buffer),2562 .unwind_info => try macho_file.unwind_info.write(macho_file, buffer),
2563 .got => try macho_file.got.write(macho_file, stream.writer()),2563 .got => try macho_file.got.write(macho_file, &stream),
2564 .stubs => try macho_file.stubs.write(macho_file, stream.writer()),2564 .stubs => try macho_file.stubs.write(macho_file, &stream),
2565 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, stream.writer()),2565 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, &stream),
2566 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, stream.writer()),2566 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, &stream),
2567 .objc_stubs => try macho_file.objc_stubs.write(macho_file, stream.writer()),2567 .objc_stubs => try macho_file.objc_stubs.write(macho_file, &stream),
2568 }2568 }
2569 }2569 }
2570 }.doWork;2570 }.doWork;
...@@ -2605,8 +2605,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {...@@ -2605,8 +2605,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {
2605 try macho_file.lazy_bind_section.updateSize(macho_file);2605 try macho_file.lazy_bind_section.updateSize(macho_file);
2606 const sect_id = macho_file.stubs_helper_sect_index.?;2606 const sect_id = macho_file.stubs_helper_sect_index.?;
2607 const out = &macho_file.sections.items(.out)[sect_id];2607 const out = &macho_file.sections.items(.out)[sect_id];
2608 var stream = std.io.fixedBufferStream(out.items);2608 var stream: Writer = .fixed(out.items);
2609 try macho_file.stubs_helper.write(macho_file, stream.writer());2609 try macho_file.stubs_helper.write(macho_file, &stream);
2610 }2610 }
2611 }.doWork;2611 }.doWork;
2612 doWork(self) catch |err|2612 doWork(self) catch |err|
...@@ -2669,18 +2669,17 @@ fn writeDyldInfo(self: *MachO) !void {...@@ -2669,18 +2669,17 @@ fn writeDyldInfo(self: *MachO) !void {
2669 defer gpa.free(buffer);2669 defer gpa.free(buffer);
2670 @memset(buffer, 0);2670 @memset(buffer, 0);
26712671
2672 var stream = std.io.fixedBufferStream(buffer);2672 var writer: Writer = .fixed(buffer);
2673 const writer = stream.writer();2673
26742674 try self.rebase_section.write(&writer);
2675 try self.rebase_section.write(writer);2675 writer.end = cmd.bind_off - base_off;
2676 try stream.seekTo(cmd.bind_off - base_off);2676 try self.bind_section.write(&writer);
2677 try self.bind_section.write(writer);2677 writer.end = cmd.weak_bind_off - base_off;
2678 try stream.seekTo(cmd.weak_bind_off - base_off);2678 try self.weak_bind_section.write(&writer);
2679 try self.weak_bind_section.write(writer);2679 writer.end = cmd.lazy_bind_off - base_off;
2680 try stream.seekTo(cmd.lazy_bind_off - base_off);2680 try self.lazy_bind_section.write(&writer);
2681 try self.lazy_bind_section.write(writer);2681 writer.end = cmd.export_off - base_off;
2682 try stream.seekTo(cmd.export_off - base_off);2682 try self.export_trie.write(&writer);
2683 try self.export_trie.write(writer);
2684 try self.pwriteAll(buffer, cmd.rebase_off);2683 try self.pwriteAll(buffer, cmd.rebase_off);
2685}2684}
26862685
...@@ -2689,10 +2688,10 @@ pub fn writeDataInCode(self: *MachO) !void {...@@ -2689,10 +2688,10 @@ pub fn writeDataInCode(self: *MachO) !void {
2689 defer tracy.end();2688 defer tracy.end();
2690 const gpa = self.base.comp.gpa;2689 const gpa = self.base.comp.gpa;
2691 const cmd = self.data_in_code_cmd;2690 const cmd = self.data_in_code_cmd;
2692 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.data_in_code.size());2691 var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.data_in_code.size());
2693 defer buffer.deinit();2692 defer buffer.deinit();
2694 try self.data_in_code.write(self, buffer.writer());2693 self.data_in_code.write(self, &buffer.writer) catch return error.OutOfMemory;
2695 try self.pwriteAll(buffer.items, cmd.dataoff);2694 try self.pwriteAll(buffer.written(), cmd.dataoff);
2696}2695}
26972696
2698fn writeIndsymtab(self: *MachO) !void {2697fn writeIndsymtab(self: *MachO) !void {
...@@ -2701,10 +2700,11 @@ fn writeIndsymtab(self: *MachO) !void {...@@ -2701,10 +2700,11 @@ fn writeIndsymtab(self: *MachO) !void {
2701 const gpa = self.base.comp.gpa;2700 const gpa = self.base.comp.gpa;
2702 const cmd = self.dysymtab_cmd;2701 const cmd = self.dysymtab_cmd;
2703 const needed_size = cmd.nindirectsyms * @sizeOf(u32);2702 const needed_size = cmd.nindirectsyms * @sizeOf(u32);
2704 var buffer = try std.array_list.Managed(u8).initCapacity(gpa, needed_size);2703 const buffer = try gpa.alloc(u8, needed_size);
2705 defer buffer.deinit();2704 defer gpa.free(buffer);
2706 try self.indsymtab.write(self, buffer.writer());2705 var writer: Writer = .fixed(buffer);
2707 try self.pwriteAll(buffer.items, cmd.indirectsymoff);2706 try self.indsymtab.write(self, &writer);
2707 try self.pwriteAll(buffer, cmd.indirectsymoff);
2708}2708}
27092709
2710pub fn writeSymtabToFile(self: *MachO) !void {2710pub fn writeSymtabToFile(self: *MachO) !void {
...@@ -2821,8 +2821,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2821,8 +2821,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2821 const buffer = try gpa.alloc(u8, needed_size);2821 const buffer = try gpa.alloc(u8, needed_size);
2822 defer gpa.free(buffer);2822 defer gpa.free(buffer);
28232823
2824 var stream = std.io.fixedBufferStream(buffer);2824 var writer: Writer = .fixed(buffer);
2825 const writer = stream.writer();
28262825
2827 var ncmds: usize = 0;2826 var ncmds: usize = 0;
28282827
...@@ -2831,26 +2830,26 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2831,26 +2830,26 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2831 const slice = self.sections.slice();2830 const slice = self.sections.slice();
2832 var sect_id: usize = 0;2831 var sect_id: usize = 0;
2833 for (self.segments.items) |seg| {2832 for (self.segments.items) |seg| {
2834 try writer.writeStruct(seg);2833 try writer.writeStruct(seg, .little);
2835 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {2834 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
2836 try writer.writeStruct(header);2835 try writer.writeStruct(header, .little);
2837 }2836 }
2838 sect_id += seg.nsects;2837 sect_id += seg.nsects;
2839 }2838 }
2840 ncmds += self.segments.items.len;2839 ncmds += self.segments.items.len;
2841 }2840 }
28422841
2843 try writer.writeStruct(self.dyld_info_cmd);2842 try writer.writeStruct(self.dyld_info_cmd, .little);
2844 ncmds += 1;2843 ncmds += 1;
2845 try writer.writeStruct(self.function_starts_cmd);2844 try writer.writeStruct(self.function_starts_cmd, .little);
2846 ncmds += 1;2845 ncmds += 1;
2847 try writer.writeStruct(self.data_in_code_cmd);2846 try writer.writeStruct(self.data_in_code_cmd, .little);
2848 ncmds += 1;2847 ncmds += 1;
2849 try writer.writeStruct(self.symtab_cmd);2848 try writer.writeStruct(self.symtab_cmd, .little);
2850 ncmds += 1;2849 ncmds += 1;
2851 try writer.writeStruct(self.dysymtab_cmd);2850 try writer.writeStruct(self.dysymtab_cmd, .little);
2852 ncmds += 1;2851 ncmds += 1;
2853 try load_commands.writeDylinkerLC(writer);2852 try load_commands.writeDylinkerLC(&writer);
2854 ncmds += 1;2853 ncmds += 1;
28552854
2856 if (self.getInternalObject()) |obj| {2855 if (self.getInternalObject()) |obj| {
...@@ -2861,44 +2860,44 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2861,44 +2860,44 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2861 02860 0
2862 else2861 else
2863 @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));2862 @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));
2864 try writer.writeStruct(macho.entry_point_command{2863 try writer.writeStruct(@as(macho.entry_point_command, .{
2865 .entryoff = entryoff,2864 .entryoff = entryoff,
2866 .stacksize = self.base.stack_size,2865 .stacksize = self.base.stack_size,
2867 });2866 }), .little);
2868 ncmds += 1;2867 ncmds += 1;
2869 }2868 }
2870 }2869 }
28712870
2872 if (self.base.isDynLib()) {2871 if (self.base.isDynLib()) {
2873 try load_commands.writeDylibIdLC(self, writer);2872 try load_commands.writeDylibIdLC(self, &writer);
2874 ncmds += 1;2873 ncmds += 1;
2875 }2874 }
28762875
2877 for (self.rpath_list) |rpath| {2876 for (self.rpath_list) |rpath| {
2878 try load_commands.writeRpathLC(rpath, writer);2877 try load_commands.writeRpathLC(rpath, &writer);
2879 ncmds += 1;2878 ncmds += 1;
2880 }2879 }
2881 if (comp.config.any_sanitize_thread) {2880 if (comp.config.any_sanitize_thread) {
2882 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);2881 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
2883 defer gpa.free(path);2882 defer gpa.free(path);
2884 const rpath = std.fs.path.dirname(path) orelse ".";2883 const rpath = std.fs.path.dirname(path) orelse ".";
2885 try load_commands.writeRpathLC(rpath, writer);2884 try load_commands.writeRpathLC(rpath, &writer);
2886 ncmds += 1;2885 ncmds += 1;
2887 }2886 }
28882887
2889 try writer.writeStruct(macho.source_version_command{ .version = 0 });2888 try writer.writeStruct(@as(macho.source_version_command, .{ .version = 0 }), .little);
2890 ncmds += 1;2889 ncmds += 1;
28912890
2892 if (self.platform.isBuildVersionCompatible()) {2891 if (self.platform.isBuildVersionCompatible()) {
2893 try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, writer);2892 try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, &writer);
2894 ncmds += 1;2893 ncmds += 1;
2895 } else {2894 } else {
2896 try load_commands.writeVersionMinLC(self.platform, self.sdk_version, writer);2895 try load_commands.writeVersionMinLC(self.platform, self.sdk_version, &writer);
2897 ncmds += 1;2896 ncmds += 1;
2898 }2897 }
28992898
2900 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos;2899 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + writer.end;
2901 try writer.writeStruct(self.uuid_cmd);2900 try writer.writeStruct(self.uuid_cmd, .little);
2902 ncmds += 1;2901 ncmds += 1;
29032902
2904 for (self.dylibs.items) |index| {2903 for (self.dylibs.items) |index| {
...@@ -2916,16 +2915,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2916,16 +2915,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2916 .timestamp = dylib_id.timestamp,2915 .timestamp = dylib_id.timestamp,
2917 .current_version = dylib_id.current_version,2916 .current_version = dylib_id.current_version,
2918 .compatibility_version = dylib_id.compatibility_version,2917 .compatibility_version = dylib_id.compatibility_version,
2919 }, writer);2918 }, &writer);
2920 ncmds += 1;2919 ncmds += 1;
2921 }2920 }
29222921
2923 if (self.requiresCodeSig()) {2922 if (self.requiresCodeSig()) {
2924 try writer.writeStruct(self.codesig_cmd);2923 try writer.writeStruct(self.codesig_cmd, .little);
2925 ncmds += 1;2924 ncmds += 1;
2926 }2925 }
29272926
2928 assert(stream.pos == needed_size);2927 assert(writer.end == needed_size);
29292928
2930 try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));2929 try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
29312930
...@@ -3014,25 +3013,26 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {...@@ -3014,25 +3013,26 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
3014pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {3013pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
3015 const seg = self.getTextSegment();3014 const seg = self.getTextSegment();
3016 const offset = self.codesig_cmd.dataoff;3015 const offset = self.codesig_cmd.dataoff;
3016 const gpa = self.base.comp.gpa;
30173017
3018 var buffer = std.array_list.Managed(u8).init(self.base.comp.gpa);3018 const buffer = try gpa.alloc(u8, code_sig.size());
3019 defer buffer.deinit();3019 defer gpa.free(buffer);
3020 try buffer.ensureTotalCapacityPrecise(code_sig.size());3020 var writer: Writer = .fixed(buffer);
3021 try code_sig.writeAdhocSignature(self, .{3021 try code_sig.writeAdhocSignature(self, .{
3022 .file = self.base.file.?,3022 .file = self.base.file.?,
3023 .exec_seg_base = seg.fileoff,3023 .exec_seg_base = seg.fileoff,
3024 .exec_seg_limit = seg.filesize,3024 .exec_seg_limit = seg.filesize,
3025 .file_size = offset,3025 .file_size = offset,
3026 .dylib = self.base.isDynLib(),3026 .dylib = self.base.isDynLib(),
3027 }, buffer.writer());3027 }, &writer);
3028 assert(buffer.items.len == code_sig.size());3028 assert(writer.buffered().len == code_sig.size());
30293029
3030 log.debug("writing code signature from 0x{x} to 0x{x}", .{3030 log.debug("writing code signature from 0x{x} to 0x{x}", .{
3031 offset,3031 offset,
3032 offset + buffer.items.len,3032 offset + writer.buffered().len,
3033 });3033 });
30343034
3035 try self.pwriteAll(buffer.items, offset);3035 try self.pwriteAll(writer.buffered(), offset);
3036}3036}
30373037
3038pub fn updateFunc(3038pub fn updateFunc(
...@@ -5372,7 +5372,7 @@ const macho = std.macho;...@@ -5372,7 +5372,7 @@ const macho = std.macho;
5372const math = std.math;5372const math = std.math;
5373const mem = std.mem;5373const mem = std.mem;
5374const meta = std.meta;5374const meta = std.meta;
5375const Writer = std.io.Writer;5375const Writer = std.Io.Writer;
53765376
5377const aarch64 = codegen.aarch64.encoding;5377const aarch64 = codegen.aarch64.encoding;
5378const bind = @import("MachO/dyld_info/bind.zig");5378const bind = @import("MachO/dyld_info/bind.zig");
src/link/MachO/Archive.zig+18-38
...@@ -81,34 +81,20 @@ pub fn writeHeader(...@@ -81,34 +81,20 @@ pub fn writeHeader(
81 object_name: []const u8,81 object_name: []const u8,
82 object_size: usize,82 object_size: usize,
83 format: Format,83 format: Format,
84 writer: anytype,84 writer: *Writer,
85) !void {85) !void {
86 var hdr: ar_hdr = .{86 var hdr: ar_hdr = .{};
87 .ar_name = undefined,
88 .ar_date = undefined,
89 .ar_uid = undefined,
90 .ar_gid = undefined,
91 .ar_mode = undefined,
92 .ar_size = undefined,
93 .ar_fmag = undefined,
94 };
95 @memset(mem.asBytes(&hdr), 0x20);
96 inline for (@typeInfo(ar_hdr).@"struct".fields) |field| {
97 var stream = std.io.fixedBufferStream(&@field(hdr, field.name));
98 stream.writer().print("0", .{}) catch unreachable;
99 }
100 @memcpy(&hdr.ar_fmag, ARFMAG);
10187
102 const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format));88 const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format));
103 const total_object_size = object_size + object_name_len;89 const total_object_size = object_size + object_name_len;
10490
105 {91 {
106 var stream = std.io.fixedBufferStream(&hdr.ar_name);92 var stream: Writer = .fixed(&hdr.ar_name);
107 stream.writer().print("#1/{d}", .{object_name_len}) catch unreachable;93 stream.print("#1/{d}", .{object_name_len}) catch unreachable;
108 }94 }
109 {95 {
110 var stream = std.io.fixedBufferStream(&hdr.ar_size);96 var stream: Writer = .fixed(&hdr.ar_size);
111 stream.writer().print("{d}", .{total_object_size}) catch unreachable;97 stream.print("{d}", .{total_object_size}) catch unreachable;
112 }98 }
11399
114 try writer.writeAll(mem.asBytes(&hdr));100 try writer.writeAll(mem.asBytes(&hdr));
...@@ -116,7 +102,7 @@ pub fn writeHeader(...@@ -116,7 +102,7 @@ pub fn writeHeader(
116102
117 const padding = object_name_len - object_name.len - 1;103 const padding = object_name_len - object_name.len - 1;
118 if (padding > 0) {104 if (padding > 0) {
119 try writer.writeByteNTimes(0, padding);105 try writer.splatByteAll(0, padding);
120 }106 }
121}107}
122108
...@@ -138,25 +124,19 @@ pub const SYMDEF64_SORTED = "__.SYMDEF_64 SORTED";...@@ -138,25 +124,19 @@ pub const SYMDEF64_SORTED = "__.SYMDEF_64 SORTED";
138124
139pub const ar_hdr = extern struct {125pub const ar_hdr = extern struct {
140 /// Member file name, sometimes / terminated.126 /// Member file name, sometimes / terminated.
141 ar_name: [16]u8,127 ar_name: [16]u8 = "0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20".*,
142
143 /// File date, decimal seconds since Epoch.128 /// File date, decimal seconds since Epoch.
144 ar_date: [12]u8,129 ar_date: [12]u8 = "0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20".*,
145
146 /// User ID, in ASCII format.130 /// User ID, in ASCII format.
147 ar_uid: [6]u8,131 ar_uid: [6]u8 = "0\x20\x20\x20\x20\x20".*,
148
149 /// Group ID, in ASCII format.132 /// Group ID, in ASCII format.
150 ar_gid: [6]u8,133 ar_gid: [6]u8 = "0\x20\x20\x20\x20\x20".*,
151
152 /// File mode, in ASCII octal.134 /// File mode, in ASCII octal.
153 ar_mode: [8]u8,135 ar_mode: [8]u8 = "0\x20\x20\x20\x20\x20\x20\x20".*,
154
155 /// File size, in ASCII decimal.136 /// File size, in ASCII decimal.
156 ar_size: [10]u8,137 ar_size: [10]u8 = "0\x20\x20\x20\x20\x20\x20\x20\x20\x20".*,
157
158 /// Always contains ARFMAG.138 /// Always contains ARFMAG.
159 ar_fmag: [2]u8,139 ar_fmag: [2]u8 = ARFMAG.*,
160140
161 fn date(self: ar_hdr) !u64 {141 fn date(self: ar_hdr) !u64 {
162 const value = mem.trimEnd(u8, &self.ar_date, &[_]u8{@as(u8, 0x20)});142 const value = mem.trimEnd(u8, &self.ar_date, &[_]u8{@as(u8, 0x20)});
...@@ -201,7 +181,7 @@ pub const ArSymtab = struct {...@@ -201,7 +181,7 @@ pub const ArSymtab = struct {
201 return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);181 return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
202 }182 }
203183
204 pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: anytype) !void {184 pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: *Writer) !void {
205 const ptr_width = ptrWidth(format);185 const ptr_width = ptrWidth(format);
206 // Header186 // Header
207 try writeHeader(SYMDEF, ar.size(format), format, writer);187 try writeHeader(SYMDEF, ar.size(format), format, writer);
...@@ -226,7 +206,7 @@ pub const ArSymtab = struct {...@@ -226,7 +206,7 @@ pub const ArSymtab = struct {
226 // Strtab206 // Strtab
227 try writer.writeAll(ar.strtab.buffer.items);207 try writer.writeAll(ar.strtab.buffer.items);
228 if (padding > 0) {208 if (padding > 0) {
229 try writer.writeByteNTimes(0, padding);209 try writer.splatByteAll(0, padding);
230 }210 }
231 }211 }
232212
...@@ -275,7 +255,7 @@ pub fn ptrWidth(format: Format) usize {...@@ -275,7 +255,7 @@ pub fn ptrWidth(format: Format) usize {
275 };255 };
276}256}
277257
278pub fn writeInt(format: Format, value: u64, writer: anytype) !void {258pub fn writeInt(format: Format, value: u64, writer: *Writer) !void {
279 switch (format) {259 switch (format) {
280 .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),260 .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
281 .p64 => try writer.writeInt(u64, value, .little),261 .p64 => try writer.writeInt(u64, value, .little),
...@@ -299,7 +279,7 @@ const mem = std.mem;...@@ -299,7 +279,7 @@ const mem = std.mem;
299const std = @import("std");279const std = @import("std");
300const Allocator = std.mem.Allocator;280const Allocator = std.mem.Allocator;
301const Path = std.Build.Cache.Path;281const Path = std.Build.Cache.Path;
302const Writer = std.io.Writer;282const Writer = std.Io.Writer;
303283
304const Archive = @This();284const Archive = @This();
305const File = @import("file.zig").File;285const File = @import("file.zig").File;
src/link/MachO/Atom.zig+6-5
...@@ -581,7 +581,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {...@@ -581,7 +581,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
581 relocs_log.debug("{x}: {s}", .{ self.value, name });581 relocs_log.debug("{x}: {s}", .{ self.value, name });
582582
583 var has_error = false;583 var has_error = false;
584 var stream = std.io.fixedBufferStream(buffer);584 var stream: Writer = .fixed(buffer);
585 var i: usize = 0;585 var i: usize = 0;
586 while (i < relocs.len) : (i += 1) {586 while (i < relocs.len) : (i += 1) {
587 const rel = relocs[i];587 const rel = relocs[i];
...@@ -592,8 +592,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {...@@ -592,8 +592,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
592 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;592 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;
593 }593 }
594594
595 try stream.seekTo(rel_offset);595 stream.end = rel_offset;
596 self.resolveRelocInner(rel, subtractor, buffer, macho_file, stream.writer()) catch |err| {596 self.resolveRelocInner(rel, subtractor, buffer, macho_file, &stream) catch |err| {
597 switch (err) {597 switch (err) {
598 error.RelaxFail => {598 error.RelaxFail => {
599 const target = switch (rel.tag) {599 const target = switch (rel.tag) {
...@@ -630,6 +630,7 @@ const ResolveError = error{...@@ -630,6 +630,7 @@ const ResolveError = error{
630 UnexpectedRemainder,630 UnexpectedRemainder,
631 Overflow,631 Overflow,
632 OutOfMemory,632 OutOfMemory,
633 WriteFailed,
633};634};
634635
635fn resolveRelocInner(636fn resolveRelocInner(
...@@ -638,7 +639,7 @@ fn resolveRelocInner(...@@ -638,7 +639,7 @@ fn resolveRelocInner(
638 subtractor: ?Relocation,639 subtractor: ?Relocation,
639 code: []u8,640 code: []u8,
640 macho_file: *MachO,641 macho_file: *MachO,
641 writer: anytype,642 writer: *Writer,
642) ResolveError!void {643) ResolveError!void {
643 const t = &macho_file.base.comp.root_mod.resolved_target.result;644 const t = &macho_file.base.comp.root_mod.resolved_target.result;
644 const cpu_arch = t.cpu.arch;645 const cpu_arch = t.cpu.arch;
...@@ -1147,7 +1148,7 @@ const math = std.math;...@@ -1147,7 +1148,7 @@ const math = std.math;
1147const mem = std.mem;1148const mem = std.mem;
1148const log = std.log.scoped(.link);1149const log = std.log.scoped(.link);
1149const relocs_log = std.log.scoped(.link_relocs);1150const relocs_log = std.log.scoped(.link_relocs);
1150const Writer = std.io.Writer;1151const Writer = std.Io.Writer;
1151const Allocator = mem.Allocator;1152const Allocator = mem.Allocator;
1152const AtomicBool = std.atomic.Value(bool);1153const AtomicBool = std.atomic.Value(bool);
11531154
src/link/MachO/CodeSignature.zig+8-8
...@@ -304,10 +304,10 @@ pub fn writeAdhocSignature(...@@ -304,10 +304,10 @@ pub fn writeAdhocSignature(
304 var hash: [hash_size]u8 = undefined;304 var hash: [hash_size]u8 = undefined;
305305
306 if (self.requirements) |*req| {306 if (self.requirements) |*req| {
307 var buf = std.array_list.Managed(u8).init(allocator);307 var a: std.Io.Writer.Allocating = .init(allocator);
308 defer buf.deinit();308 defer a.deinit();
309 try req.write(buf.writer());309 try req.write(&a.writer);
310 Sha256.hash(buf.items, &hash, .{});310 Sha256.hash(a.written(), &hash, .{});
311 self.code_directory.addSpecialHash(req.slotType(), hash);311 self.code_directory.addSpecialHash(req.slotType(), hash);
312312
313 try blobs.append(.{ .requirements = req });313 try blobs.append(.{ .requirements = req });
...@@ -316,10 +316,10 @@ pub fn writeAdhocSignature(...@@ -316,10 +316,10 @@ pub fn writeAdhocSignature(
316 }316 }
317317
318 if (self.entitlements) |*ents| {318 if (self.entitlements) |*ents| {
319 var buf = std.array_list.Managed(u8).init(allocator);319 var a: std.Io.Writer.Allocating = .init(allocator);
320 defer buf.deinit();320 defer a.deinit();
321 try ents.write(buf.writer());321 try ents.write(&a.writer);
322 Sha256.hash(buf.items, &hash, .{});322 Sha256.hash(a.written(), &hash, .{});
323 self.code_directory.addSpecialHash(ents.slotType(), hash);323 self.code_directory.addSpecialHash(ents.slotType(), hash);
324324
325 try blobs.append(.{ .entitlements = ents });325 try blobs.append(.{ .entitlements = ents });
src/link/MachO/DebugSymbols.zig+9-10
...@@ -273,14 +273,13 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -273,14 +273,13 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
273 const buffer = try gpa.alloc(u8, needed_size);273 const buffer = try gpa.alloc(u8, needed_size);
274 defer gpa.free(buffer);274 defer gpa.free(buffer);
275275
276 var stream = std.io.fixedBufferStream(buffer);276 var writer: Writer = .fixed(buffer);
277 const writer = stream.writer();
278277
279 var ncmds: usize = 0;278 var ncmds: usize = 0;
280279
281 // UUID comes first presumably to speed up lookup by the consumer like lldb.280 // UUID comes first presumably to speed up lookup by the consumer like lldb.
282 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);281 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);
283 try writer.writeStruct(self.uuid_cmd);282 try writer.writeStruct(self.uuid_cmd, .little);
284 ncmds += 1;283 ncmds += 1;
285284
286 // Segment and section load commands285 // Segment and section load commands
...@@ -293,11 +292,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -293,11 +292,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
293 var out_seg = seg;292 var out_seg = seg;
294 out_seg.fileoff = 0;293 out_seg.fileoff = 0;
295 out_seg.filesize = 0;294 out_seg.filesize = 0;
296 try writer.writeStruct(out_seg);295 try writer.writeStruct(out_seg, .little);
297 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {296 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
298 var out_header = header;297 var out_header = header;
299 out_header.offset = 0;298 out_header.offset = 0;
300 try writer.writeStruct(out_header);299 try writer.writeStruct(out_header, .little);
301 }300 }
302 sect_id += seg.nsects;301 sect_id += seg.nsects;
303 }302 }
...@@ -306,19 +305,19 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -306,19 +305,19 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
306 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.305 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
307 sect_id = 0;306 sect_id = 0;
308 for (self.segments.items) |seg| {307 for (self.segments.items) |seg| {
309 try writer.writeStruct(seg);308 try writer.writeStruct(seg, .little);
310 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {309 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
311 try writer.writeStruct(header);310 try writer.writeStruct(header, .little);
312 }311 }
313 sect_id += seg.nsects;312 sect_id += seg.nsects;
314 }313 }
315 ncmds += self.segments.items.len;314 ncmds += self.segments.items.len;
316 }315 }
317316
318 try writer.writeStruct(self.symtab_cmd);317 try writer.writeStruct(self.symtab_cmd, .little);
319 ncmds += 1;318 ncmds += 1;
320319
321 assert(stream.pos == needed_size);320 assert(writer.end == needed_size);
322321
323 try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));322 try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
324323
...@@ -460,7 +459,7 @@ const math = std.math;...@@ -460,7 +459,7 @@ const math = std.math;
460const mem = std.mem;459const mem = std.mem;
461const padToIdeal = MachO.padToIdeal;460const padToIdeal = MachO.padToIdeal;
462const trace = @import("../../tracy.zig").trace;461const trace = @import("../../tracy.zig").trace;
463const Writer = std.io.Writer;462const Writer = std.Io.Writer;
464463
465const Allocator = mem.Allocator;464const Allocator = mem.Allocator;
466const MachO = @import("../MachO.zig");465const MachO = @import("../MachO.zig");
src/link/MachO/InternalObject.zig+1-1
...@@ -261,7 +261,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil...@@ -261,7 +261,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
261261
262 sect.offset = @intCast(self.objc_methnames.items.len);262 sect.offset = @intCast(self.objc_methnames.items.len);
263 try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);263 try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);
264 self.objc_methnames.writer(gpa).print("{s}\x00", .{methname}) catch unreachable;264 self.objc_methnames.print(gpa, "{s}\x00", .{methname}) catch unreachable;
265265
266 const name_str = try self.addString(gpa, "ltmp");266 const name_str = try self.addString(gpa, "ltmp");
267 const sym_index = try self.addSymbol(gpa);267 const sym_index = try self.addSymbol(gpa);
src/link/MachO/UnwindInfo.zig+23-24
...@@ -293,8 +293,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -293,8 +293,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
293 const seg = macho_file.getTextSegment();293 const seg = macho_file.getTextSegment();
294 const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];294 const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];
295295
296 var stream = std.io.fixedBufferStream(buffer);296 var writer: Writer = .fixed(buffer);
297 const writer = stream.writer();
298297
299 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);298 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);
300 const common_encodings_count: u32 = info.common_encodings_count;299 const common_encodings_count: u32 = info.common_encodings_count;
...@@ -303,14 +302,14 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -303,14 +302,14 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
303 const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);302 const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);
304 const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));303 const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));
305304
306 try writer.writeStruct(macho.unwind_info_section_header{305 try writer.writeStruct(@as(macho.unwind_info_section_header, .{
307 .commonEncodingsArraySectionOffset = common_encodings_offset,306 .commonEncodingsArraySectionOffset = common_encodings_offset,
308 .commonEncodingsArrayCount = common_encodings_count,307 .commonEncodingsArrayCount = common_encodings_count,
309 .personalityArraySectionOffset = personalities_offset,308 .personalityArraySectionOffset = personalities_offset,
310 .personalityArrayCount = personalities_count,309 .personalityArrayCount = personalities_count,
311 .indexSectionOffset = indexes_offset,310 .indexSectionOffset = indexes_offset,
312 .indexCount = indexes_count,311 .indexCount = indexes_count,
313 });312 }), .little);
314313
315 try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));314 try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));
316315
...@@ -325,42 +324,42 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -325,42 +324,42 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
325 for (info.pages.items, 0..) |page, i| {324 for (info.pages.items, 0..) |page, i| {
326 assert(page.count > 0);325 assert(page.count > 0);
327 const rec = info.records.items[page.start].getUnwindRecord(macho_file);326 const rec = info.records.items[page.start].getUnwindRecord(macho_file);
328 try writer.writeStruct(macho.unwind_info_section_header_index_entry{327 try writer.writeStruct(@as(macho.unwind_info_section_header_index_entry, .{
329 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),328 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
330 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),329 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
331 .lsdaIndexArraySectionOffset = lsda_base_offset +330 .lsdaIndexArraySectionOffset = lsda_base_offset +
332 info.lsdas_lookup.items[page.start] * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),331 info.lsdas_lookup.items[page.start] * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),
333 });332 }), .little);
334 }333 }
335334
336 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);335 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);
337 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));336 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));
338 try writer.writeStruct(macho.unwind_info_section_header_index_entry{337 try writer.writeStruct(@as(macho.unwind_info_section_header_index_entry, .{
339 .functionOffset = sentinel_address,338 .functionOffset = sentinel_address,
340 .secondLevelPagesSectionOffset = 0,339 .secondLevelPagesSectionOffset = 0,
341 .lsdaIndexArraySectionOffset = lsda_base_offset +340 .lsdaIndexArraySectionOffset = lsda_base_offset +
342 @as(u32, @intCast(info.lsdas.items.len)) * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),341 @as(u32, @intCast(info.lsdas.items.len)) * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),
343 });342 }), .little);
344343
345 for (info.lsdas.items) |index| {344 for (info.lsdas.items) |index| {
346 const rec = info.records.items[index].getUnwindRecord(macho_file);345 const rec = info.records.items[index].getUnwindRecord(macho_file);
347 try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{346 try writer.writeStruct(@as(macho.unwind_info_section_header_lsda_index_entry, .{
348 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),347 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
349 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),348 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),
350 });349 }), .little);
351 }350 }
352351
353 for (info.pages.items) |page| {352 for (info.pages.items) |page| {
354 const start = stream.pos;353 const start = writer.end;
355 try page.write(info, macho_file, writer);354 try page.write(info, macho_file, &writer);
356 const nwritten = stream.pos - start;355 const nwritten = writer.end - start;
357 if (nwritten < second_level_page_bytes) {356 if (nwritten < second_level_page_bytes) {
358 const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;357 const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;
359 try writer.writeByteNTimes(0, padding);358 try writer.splatByteAll(0, padding);
360 }359 }
361 }360 }
362361
363 @memset(buffer[stream.pos..], 0);362 @memset(buffer[writer.end..], 0);
364}363}
365364
366fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {365fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {
...@@ -611,33 +610,33 @@ const Page = struct {...@@ -611,33 +610,33 @@ const Page = struct {
611 } };610 } };
612 }611 }
613612
614 fn write(page: Page, info: UnwindInfo, macho_file: *MachO, writer: anytype) !void {613 fn write(page: Page, info: UnwindInfo, macho_file: *MachO, writer: *Writer) !void {
615 const seg = macho_file.getTextSegment();614 const seg = macho_file.getTextSegment();
616615
617 switch (page.kind) {616 switch (page.kind) {
618 .regular => {617 .regular => {
619 try writer.writeStruct(macho.unwind_info_regular_second_level_page_header{618 try writer.writeStruct(@as(macho.unwind_info_regular_second_level_page_header, .{
620 .entryPageOffset = @sizeOf(macho.unwind_info_regular_second_level_page_header),619 .entryPageOffset = @sizeOf(macho.unwind_info_regular_second_level_page_header),
621 .entryCount = page.count,620 .entryCount = page.count,
622 });621 }), .little);
623622
624 for (info.records.items[page.start..][0..page.count]) |ref| {623 for (info.records.items[page.start..][0..page.count]) |ref| {
625 const rec = ref.getUnwindRecord(macho_file);624 const rec = ref.getUnwindRecord(macho_file);
626 try writer.writeStruct(macho.unwind_info_regular_second_level_entry{625 try writer.writeStruct(@as(macho.unwind_info_regular_second_level_entry, .{
627 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),626 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
628 .encoding = rec.enc.enc,627 .encoding = rec.enc.enc,
629 });628 }), .little);
630 }629 }
631 },630 },
632 .compressed => {631 .compressed => {
633 const entry_offset = @sizeOf(macho.unwind_info_compressed_second_level_page_header) +632 const entry_offset = @sizeOf(macho.unwind_info_compressed_second_level_page_header) +
634 @as(u16, @intCast(page.page_encodings_count)) * @sizeOf(u32);633 @as(u16, @intCast(page.page_encodings_count)) * @sizeOf(u32);
635 try writer.writeStruct(macho.unwind_info_compressed_second_level_page_header{634 try writer.writeStruct(@as(macho.unwind_info_compressed_second_level_page_header, .{
636 .entryPageOffset = entry_offset,635 .entryPageOffset = entry_offset,
637 .entryCount = page.count,636 .entryCount = page.count,
638 .encodingsPageOffset = @sizeOf(macho.unwind_info_compressed_second_level_page_header),637 .encodingsPageOffset = @sizeOf(macho.unwind_info_compressed_second_level_page_header),
639 .encodingsCount = page.page_encodings_count,638 .encodingsCount = page.page_encodings_count,
640 });639 }), .little);
641640
642 for (page.page_encodings[0..page.page_encodings_count]) |enc| {641 for (page.page_encodings[0..page.page_encodings_count]) |enc| {
643 try writer.writeInt(u32, enc.enc, .little);642 try writer.writeInt(u32, enc.enc, .little);
...@@ -656,7 +655,7 @@ const Page = struct {...@@ -656,7 +655,7 @@ const Page = struct {
656 .funcOffset = @as(u24, @intCast(rec.getAtomAddress(macho_file) - first_rec.getAtomAddress(macho_file))),655 .funcOffset = @as(u24, @intCast(rec.getAtomAddress(macho_file) - first_rec.getAtomAddress(macho_file))),
657 .encodingIndex = @as(u8, @intCast(enc_index)),656 .encodingIndex = @as(u8, @intCast(enc_index)),
658 };657 };
659 try writer.writeStruct(compressed);658 try writer.writeStruct(compressed, .little);
660 }659 }
661 },660 },
662 }661 }
...@@ -673,7 +672,7 @@ const macho = std.macho;...@@ -673,7 +672,7 @@ const macho = std.macho;
673const math = std.math;672const math = std.math;
674const mem = std.mem;673const mem = std.mem;
675const trace = @import("../../tracy.zig").trace;674const trace = @import("../../tracy.zig").trace;
676const Writer = std.io.Writer;675const Writer = std.Io.Writer;
677676
678const Allocator = mem.Allocator;677const Allocator = mem.Allocator;
679const Atom = @import("Atom.zig");678const Atom = @import("Atom.zig");
src/link/MachO/dyld_info/Rebase.zig+4-2
...@@ -110,12 +110,14 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {...@@ -110,12 +110,14 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
110fn finalize(rebase: *Rebase, gpa: Allocator) !void {110fn finalize(rebase: *Rebase, gpa: Allocator) !void {
111 if (rebase.entries.items.len == 0) return;111 if (rebase.entries.items.len == 0) return;
112112
113 const writer = rebase.buffer.writer(gpa);
114
115 log.debug("rebase opcodes", .{});113 log.debug("rebase opcodes", .{});
116114
117 std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);115 std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);
118116
117 var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &rebase.buffer);
118 defer rebase.buffer = allocating.toArrayList();
119 const writer = &allocating.writer;
120
119 try setTypePointer(writer);121 try setTypePointer(writer);
120122
121 var start: usize = 0;123 var start: usize = 0;
src/link/MachO/dyld_info/Trie.zig+15-10
...@@ -170,8 +170,13 @@ fn finalize(self: *Trie, allocator: Allocator) !void {...@@ -170,8 +170,13 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
170 }170 }
171171
172 try self.buffer.ensureTotalCapacityPrecise(allocator, size);172 try self.buffer.ensureTotalCapacityPrecise(allocator, size);
173
174 var allocating: std.Io.Writer.Allocating = .fromArrayList(allocator, &self.buffer);
175 defer self.buffer = allocating.toArrayList();
176 const writer = &allocating.writer;
177
173 for (ordered_nodes.items) |node_index| {178 for (ordered_nodes.items) |node_index| {
174 try self.writeNode(node_index, self.buffer.writer(allocator));179 try self.writeNode(node_index, writer);
175 }180 }
176}181}
177182
...@@ -232,7 +237,7 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {...@@ -232,7 +237,7 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {
232 self.buffer.deinit(allocator);237 self.buffer.deinit(allocator);
233}238}
234239
235pub fn write(self: Trie, writer: anytype) !void {240pub fn write(self: Trie, writer: *std.Io.Writer) !void {
236 if (self.buffer.items.len == 0) return;241 if (self.buffer.items.len == 0) return;
237 try writer.writeAll(self.buffer.items);242 try writer.writeAll(self.buffer.items);
238}243}
...@@ -243,7 +248,7 @@ pub fn write(self: Trie, writer: anytype) !void {...@@ -243,7 +248,7 @@ pub fn write(self: Trie, writer: anytype) !void {
243/// iterate over `Trie.ordered_nodes` and call this method on each node.248/// iterate over `Trie.ordered_nodes` and call this method on each node.
244/// This is one of the requirements of the MachO.249/// This is one of the requirements of the MachO.
245/// Panics if `finalize` was not called before calling this method.250/// Panics if `finalize` was not called before calling this method.
246fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {251fn writeNode(self: *Trie, node_index: Node.Index, writer: *std.Io.Writer) !void {
247 const slice = self.nodes.slice();252 const slice = self.nodes.slice();
248 const edges = slice.items(.edges)[node_index];253 const edges = slice.items(.edges)[node_index];
249 const is_terminal = slice.items(.is_terminal)[node_index];254 const is_terminal = slice.items(.is_terminal)[node_index];
...@@ -253,21 +258,21 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {...@@ -253,21 +258,21 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
253 if (is_terminal) {258 if (is_terminal) {
254 // Terminal node info: encode export flags and vmaddr offset of this symbol.259 // Terminal node info: encode export flags and vmaddr offset of this symbol.
255 var info_buf: [@sizeOf(u64) * 2]u8 = undefined;260 var info_buf: [@sizeOf(u64) * 2]u8 = undefined;
256 var info_stream = std.io.fixedBufferStream(&info_buf);261 var info_stream: std.Io.Writer = .fixed(&info_buf);
257 // TODO Implement for special flags.262 // TODO Implement for special flags.
258 assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and263 assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
259 export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);264 export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
260 try leb.writeUleb128(info_stream.writer(), export_flags);265 try leb.writeUleb128(&info_stream, export_flags);
261 try leb.writeUleb128(info_stream.writer(), vmaddr_offset);266 try leb.writeUleb128(&info_stream, vmaddr_offset);
262267
263 // Encode the size of the terminal node info.268 // Encode the size of the terminal node info.
264 var size_buf: [@sizeOf(u64)]u8 = undefined;269 var size_buf: [@sizeOf(u64)]u8 = undefined;
265 var size_stream = std.io.fixedBufferStream(&size_buf);270 var size_stream: std.Io.Writer = .fixed(&size_buf);
266 try leb.writeUleb128(size_stream.writer(), info_stream.pos);271 try leb.writeUleb128(&size_stream, info_stream.end);
267272
268 // Now, write them to the output stream.273 // Now, write them to the output stream.
269 try writer.writeAll(size_buf[0..size_stream.pos]);274 try writer.writeAll(size_buf[0..size_stream.end]);
270 try writer.writeAll(info_buf[0..info_stream.pos]);275 try writer.writeAll(info_buf[0..info_stream.end]);
271 } else {276 } else {
272 // Non-terminal node is delimited by 0 byte.277 // Non-terminal node is delimited by 0 byte.
273 try writer.writeByte(0);278 try writer.writeByte(0);
src/link/MachO/dyld_info/bind.zig+26-21
...@@ -132,12 +132,14 @@ pub const Bind = struct {...@@ -132,12 +132,14 @@ pub const Bind = struct {
132 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {132 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
133 if (self.entries.items.len == 0) return;133 if (self.entries.items.len == 0) return;
134134
135 const writer = self.buffer.writer(gpa);
136
137 log.debug("bind opcodes", .{});135 log.debug("bind opcodes", .{});
138136
139 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);137 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
140138
139 var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &self.buffer);
140 defer self.buffer = allocating.toArrayList();
141 const writer = &allocating.writer;
142
141 var start: usize = 0;143 var start: usize = 0;
142 var seg_id: ?u8 = null;144 var seg_id: ?u8 = null;
143 for (self.entries.items, 0..) |entry, i| {145 for (self.entries.items, 0..) |entry, i| {
...@@ -151,7 +153,7 @@ pub const Bind = struct {...@@ -151,7 +153,7 @@ pub const Bind = struct {
151 try done(writer);153 try done(writer);
152 }154 }
153155
154 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {156 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: *std.Io.Writer) !void {
155 if (entries.len == 0) return;157 if (entries.len == 0) return;
156158
157 const seg_id = entries[0].segment_id;159 const seg_id = entries[0].segment_id;
...@@ -263,7 +265,7 @@ pub const Bind = struct {...@@ -263,7 +265,7 @@ pub const Bind = struct {
263 }265 }
264 }266 }
265267
266 pub fn write(self: Self, writer: anytype) !void {268 pub fn write(self: Self, writer: *std.Io.Writer) !void {
267 try writer.writeAll(self.buffer.items);269 try writer.writeAll(self.buffer.items);
268 }270 }
269};271};
...@@ -385,12 +387,14 @@ pub const WeakBind = struct {...@@ -385,12 +387,14 @@ pub const WeakBind = struct {
385 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {387 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
386 if (self.entries.items.len == 0) return;388 if (self.entries.items.len == 0) return;
387389
388 const writer = self.buffer.writer(gpa);
389
390 log.debug("weak bind opcodes", .{});390 log.debug("weak bind opcodes", .{});
391391
392 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);392 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
393393
394 var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &self.buffer);
395 defer self.buffer = allocating.toArrayList();
396 const writer = &allocating.writer;
397
394 var start: usize = 0;398 var start: usize = 0;
395 var seg_id: ?u8 = null;399 var seg_id: ?u8 = null;
396 for (self.entries.items, 0..) |entry, i| {400 for (self.entries.items, 0..) |entry, i| {
...@@ -404,7 +408,7 @@ pub const WeakBind = struct {...@@ -404,7 +408,7 @@ pub const WeakBind = struct {
404 try done(writer);408 try done(writer);
405 }409 }
406410
407 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {411 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: *std.Io.Writer) !void {
408 if (entries.len == 0) return;412 if (entries.len == 0) return;
409413
410 const seg_id = entries[0].segment_id;414 const seg_id = entries[0].segment_id;
...@@ -505,7 +509,7 @@ pub const WeakBind = struct {...@@ -505,7 +509,7 @@ pub const WeakBind = struct {
505 }509 }
506 }510 }
507511
508 pub fn write(self: Self, writer: anytype) !void {512 pub fn write(self: Self, writer: *std.Io.Writer) !void {
509 try writer.writeAll(self.buffer.items);513 try writer.writeAll(self.buffer.items);
510 }514 }
511};515};
...@@ -555,8 +559,6 @@ pub const LazyBind = struct {...@@ -555,8 +559,6 @@ pub const LazyBind = struct {
555 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {559 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
556 try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);560 try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);
557561
558 const writer = self.buffer.writer(gpa);
559
560 log.debug("lazy bind opcodes", .{});562 log.debug("lazy bind opcodes", .{});
561563
562 var addend: i64 = 0;564 var addend: i64 = 0;
...@@ -578,6 +580,9 @@ pub const LazyBind = struct {...@@ -578,6 +580,9 @@ pub const LazyBind = struct {
578 break :ord macho.BIND_SPECIAL_DYLIB_SELF;580 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
579 };581 };
580582
583 var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &self.buffer);
584 defer self.buffer = allocating.toArrayList();
585 const writer = &allocating.writer;
581 try setSegmentOffset(entry.segment_id, entry.offset, writer);586 try setSegmentOffset(entry.segment_id, entry.offset, writer);
582 try setSymbol(name, flags, writer);587 try setSymbol(name, flags, writer);
583 try setDylibOrdinal(ordinal, writer);588 try setDylibOrdinal(ordinal, writer);
...@@ -592,30 +597,30 @@ pub const LazyBind = struct {...@@ -592,30 +597,30 @@ pub const LazyBind = struct {
592 }597 }
593 }598 }
594599
595 pub fn write(self: Self, writer: anytype) !void {600 pub fn write(self: Self, writer: *std.Io.Writer) !void {
596 try writer.writeAll(self.buffer.items);601 try writer.writeAll(self.buffer.items);
597 }602 }
598};603};
599604
600fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {605fn setSegmentOffset(segment_id: u8, offset: u64, writer: *std.Io.Writer) !void {
601 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });606 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
602 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));607 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
603 try std.leb.writeUleb128(writer, offset);608 try std.leb.writeUleb128(writer, offset);
604}609}
605610
606fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void {611fn setSymbol(name: []const u8, flags: u8, writer: *std.Io.Writer) !void {
607 log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });612 log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });
608 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags)));613 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags)));
609 try writer.writeAll(name);614 try writer.writeAll(name);
610 try writer.writeByte(0);615 try writer.writeByte(0);
611}616}
612617
613fn setTypePointer(writer: anytype) !void {618fn setTypePointer(writer: *std.Io.Writer) !void {
614 log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});619 log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});
615 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER)));620 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER)));
616}621}
617622
618fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {623fn setDylibOrdinal(ordinal: i16, writer: *std.Io.Writer) !void {
619 if (ordinal <= 0) {624 if (ordinal <= 0) {
620 switch (ordinal) {625 switch (ordinal) {
621 macho.BIND_SPECIAL_DYLIB_SELF,626 macho.BIND_SPECIAL_DYLIB_SELF,
...@@ -639,18 +644,18 @@ fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {...@@ -639,18 +644,18 @@ fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {
639 }644 }
640}645}
641646
642fn setAddend(addend: i64, writer: anytype) !void {647fn setAddend(addend: i64, writer: *std.Io.Writer) !void {
643 log.debug(">>> set addend: {x}", .{addend});648 log.debug(">>> set addend: {x}", .{addend});
644 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);649 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
645 try std.leb.writeIleb128(writer, addend);650 try std.leb.writeIleb128(writer, addend);
646}651}
647652
648fn doBind(writer: anytype) !void {653fn doBind(writer: *std.Io.Writer) !void {
649 log.debug(">>> bind", .{});654 log.debug(">>> bind", .{});
650 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);655 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
651}656}
652657
653fn doBindAddAddr(addr: u64, writer: anytype) !void {658fn doBindAddAddr(addr: u64, writer: *std.Io.Writer) !void {
654 log.debug(">>> bind with add: {x}", .{addr});659 log.debug(">>> bind with add: {x}", .{addr});
655 if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {660 if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {
656 const imm = @divExact(addr, @sizeOf(u64));661 const imm = @divExact(addr, @sizeOf(u64));
...@@ -665,20 +670,20 @@ fn doBindAddAddr(addr: u64, writer: anytype) !void {...@@ -665,20 +670,20 @@ fn doBindAddAddr(addr: u64, writer: anytype) !void {
665 try std.leb.writeUleb128(writer, addr);670 try std.leb.writeUleb128(writer, addr);
666}671}
667672
668fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void {673fn doBindTimesSkip(count: usize, skip: u64, writer: *std.Io.Writer) !void {
669 log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });674 log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });
670 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);675 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
671 try std.leb.writeUleb128(writer, count);676 try std.leb.writeUleb128(writer, count);
672 try std.leb.writeUleb128(writer, skip);677 try std.leb.writeUleb128(writer, skip);
673}678}
674679
675fn addAddr(addr: u64, writer: anytype) !void {680fn addAddr(addr: u64, writer: *std.Io.Writer) !void {
676 log.debug(">>> add: {x}", .{addr});681 log.debug(">>> add: {x}", .{addr});
677 try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);682 try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
678 try std.leb.writeUleb128(writer, addr);683 try std.leb.writeUleb128(writer, addr);
679}684}
680685
681fn done(writer: anytype) !void {686fn done(writer: *std.Io.Writer) !void {
682 log.debug(">>> done", .{});687 log.debug(">>> done", .{});
683 try writer.writeByte(macho.BIND_OPCODE_DONE);688 try writer.writeByte(macho.BIND_OPCODE_DONE);
684}689}
src/link/MachO/load_commands.zig+19-19
...@@ -3,9 +3,9 @@ const assert = std.debug.assert;...@@ -3,9 +3,9 @@ const assert = std.debug.assert;
3const log = std.log.scoped(.link);3const log = std.log.scoped(.link);
4const macho = std.macho;4const macho = std.macho;
5const mem = std.mem;5const mem = std.mem;
6const Writer = std.io.Writer;6const Writer = std.Io.Writer;
7const Allocator = std.mem.Allocator;
78
8const Allocator = mem.Allocator;
9const DebugSymbols = @import("DebugSymbols.zig");9const DebugSymbols = @import("DebugSymbols.zig");
10const Dylib = @import("Dylib.zig");10const Dylib = @import("Dylib.zig");
11const MachO = @import("../MachO.zig");11const MachO = @import("../MachO.zig");
...@@ -181,22 +181,22 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {...@@ -181,22 +181,22 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
181 return offset;181 return offset;
182}182}
183183
184pub fn writeDylinkerLC(writer: anytype) !void {184pub fn writeDylinkerLC(writer: *Writer) !void {
185 const name_len = mem.sliceTo(default_dyld_path, 0).len;185 const name_len = mem.sliceTo(default_dyld_path, 0).len;
186 const cmdsize = @as(u32, @intCast(mem.alignForward(186 const cmdsize = @as(u32, @intCast(mem.alignForward(
187 u64,187 u64,
188 @sizeOf(macho.dylinker_command) + name_len,188 @sizeOf(macho.dylinker_command) + name_len,
189 @sizeOf(u64),189 @sizeOf(u64),
190 )));190 )));
191 try writer.writeStruct(macho.dylinker_command{191 try writer.writeStruct(@as(macho.dylinker_command, .{
192 .cmd = .LOAD_DYLINKER,192 .cmd = .LOAD_DYLINKER,
193 .cmdsize = cmdsize,193 .cmdsize = cmdsize,
194 .name = @sizeOf(macho.dylinker_command),194 .name = @sizeOf(macho.dylinker_command),
195 });195 }), .little);
196 try writer.writeAll(mem.sliceTo(default_dyld_path, 0));196 try writer.writeAll(mem.sliceTo(default_dyld_path, 0));
197 const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;197 const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;
198 if (padding > 0) {198 if (padding > 0) {
199 try writer.writeByteNTimes(0, padding);199 try writer.splatByteAll(0, padding);
200 }200 }
201}201}
202202
...@@ -208,14 +208,14 @@ const WriteDylibLCCtx = struct {...@@ -208,14 +208,14 @@ const WriteDylibLCCtx = struct {
208 compatibility_version: u32 = 0x10000,208 compatibility_version: u32 = 0x10000,
209};209};
210210
211pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {211pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: *Writer) !void {
212 const name_len = ctx.name.len + 1;212 const name_len = ctx.name.len + 1;
213 const cmdsize = @as(u32, @intCast(mem.alignForward(213 const cmdsize = @as(u32, @intCast(mem.alignForward(
214 u64,214 u64,
215 @sizeOf(macho.dylib_command) + name_len,215 @sizeOf(macho.dylib_command) + name_len,
216 @sizeOf(u64),216 @sizeOf(u64),
217 )));217 )));
218 try writer.writeStruct(macho.dylib_command{218 try writer.writeStruct(@as(macho.dylib_command, .{
219 .cmd = ctx.cmd,219 .cmd = ctx.cmd,
220 .cmdsize = cmdsize,220 .cmdsize = cmdsize,
221 .dylib = .{221 .dylib = .{
...@@ -224,16 +224,16 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {...@@ -224,16 +224,16 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
224 .current_version = ctx.current_version,224 .current_version = ctx.current_version,
225 .compatibility_version = ctx.compatibility_version,225 .compatibility_version = ctx.compatibility_version,
226 },226 },
227 });227 }), .little);
228 try writer.writeAll(ctx.name);228 try writer.writeAll(ctx.name);
229 try writer.writeByte(0);229 try writer.writeByte(0);
230 const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;230 const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;
231 if (padding > 0) {231 if (padding > 0) {
232 try writer.writeByteNTimes(0, padding);232 try writer.splatByteAll(0, padding);
233 }233 }
234}234}
235235
236pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {236pub fn writeDylibIdLC(macho_file: *MachO, writer: *Writer) !void {
237 const comp = macho_file.base.comp;237 const comp = macho_file.base.comp;
238 const gpa = comp.gpa;238 const gpa = comp.gpa;
239 assert(comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);239 assert(comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic);
...@@ -259,26 +259,26 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {...@@ -259,26 +259,26 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
259 }, writer);259 }, writer);
260}260}
261261
262pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {262pub fn writeRpathLC(rpath: []const u8, writer: *Writer) !void {
263 const rpath_len = rpath.len + 1;263 const rpath_len = rpath.len + 1;
264 const cmdsize = @as(u32, @intCast(mem.alignForward(264 const cmdsize = @as(u32, @intCast(mem.alignForward(
265 u64,265 u64,
266 @sizeOf(macho.rpath_command) + rpath_len,266 @sizeOf(macho.rpath_command) + rpath_len,
267 @sizeOf(u64),267 @sizeOf(u64),
268 )));268 )));
269 try writer.writeStruct(macho.rpath_command{269 try writer.writeStruct(@as(macho.rpath_command, .{
270 .cmdsize = cmdsize,270 .cmdsize = cmdsize,
271 .path = @sizeOf(macho.rpath_command),271 .path = @sizeOf(macho.rpath_command),
272 });272 }), .little);
273 try writer.writeAll(rpath);273 try writer.writeAll(rpath);
274 try writer.writeByte(0);274 try writer.writeByte(0);
275 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;275 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
276 if (padding > 0) {276 if (padding > 0) {
277 try writer.writeByteNTimes(0, padding);277 try writer.splatByteAll(0, padding);
278 }278 }
279}279}
280280
281pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {281pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: *Writer) !void {
282 const cmd: macho.LC = switch (platform.os_tag) {282 const cmd: macho.LC = switch (platform.os_tag) {
283 .macos => .VERSION_MIN_MACOSX,283 .macos => .VERSION_MIN_MACOSX,
284 .ios => .VERSION_MIN_IPHONEOS,284 .ios => .VERSION_MIN_IPHONEOS,
...@@ -296,9 +296,9 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer...@@ -296,9 +296,9 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer
296 }));296 }));
297}297}
298298
299pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {299pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: *Writer) !void {
300 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);300 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
301 try writer.writeStruct(macho.build_version_command{301 try writer.writeStruct(@as(macho.build_version_command, .{
302 .cmdsize = cmdsize,302 .cmdsize = cmdsize,
303 .platform = platform.toApplePlatform(),303 .platform = platform.toApplePlatform(),
304 .minos = platform.toAppleVersion(),304 .minos = platform.toAppleVersion(),
...@@ -307,7 +307,7 @@ pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticV...@@ -307,7 +307,7 @@ pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticV
307 else307 else
308 platform.toAppleVersion(),308 platform.toAppleVersion(),
309 .ntools = 1,309 .ntools = 1,
310 });310 }), .little);
311 try writer.writeAll(mem.asBytes(&macho.build_tool_version{311 try writer.writeAll(mem.asBytes(&macho.build_tool_version{
312 .tool = .ZIG,312 .tool = .ZIG,
313 .version = 0x0,313 .version = 0x0,
src/link/MachO/relocatable.zig+29-33
...@@ -205,35 +205,32 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -205,35 +205,32 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
205 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});205 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
206 }206 }
207207
208 var buffer = std.array_list.Managed(u8).init(gpa);208 const buffer = try gpa.alloc(u8, total_size);
209 defer buffer.deinit();209 defer gpa.free(buffer);
210 try buffer.ensureTotalCapacityPrecise(total_size);210 var writer: Writer = .fixed(buffer);
211 const writer = buffer.writer();
212211
213 // Write magic212 // Write magic
214 try writer.writeAll(Archive.ARMAG);213 writer.writeAll(Archive.ARMAG) catch unreachable;
215214
216 // Write symtab215 // Write symtab
217 ar_symtab.write(format, macho_file, writer) catch |err| switch (err) {216 ar_symtab.write(format, macho_file, &writer) catch |err|
218 error.OutOfMemory => return error.OutOfMemory,217 return diags.fail("failed to write archive symbol table: {t}", .{err});
219 else => |e| return diags.fail("failed to write archive symbol table: {s}", .{@errorName(e)}),
220 };
221218
222 // Write object files219 // Write object files
223 for (files.items) |index| {220 for (files.items) |index| {
224 const aligned = mem.alignForward(usize, buffer.items.len, 2);221 const aligned = mem.alignForward(usize, writer.end, 2);
225 const padding = aligned - buffer.items.len;222 const padding = aligned - writer.end;
226 if (padding > 0) {223 if (padding > 0) {
227 try writer.writeByteNTimes(0, padding);224 writer.splatByteAll(0, padding) catch unreachable;
228 }225 }
229 macho_file.getFile(index).?.writeAr(format, macho_file, writer) catch |err|226 macho_file.getFile(index).?.writeAr(format, macho_file, &writer) catch |err|
230 return diags.fail("failed to write archive: {s}", .{@errorName(err)});227 return diags.fail("failed to write archive: {t}", .{err});
231 }228 }
232229
233 assert(buffer.items.len == total_size);230 assert(writer.end == total_size);
234231
235 try macho_file.setEndPos(total_size);232 try macho_file.setEndPos(total_size);
236 try macho_file.pwriteAll(buffer.items, 0);233 try macho_file.pwriteAll(writer.buffered(), 0);
237234
238 if (diags.hasErrors()) return error.LinkFailure;235 if (diags.hasErrors()) return error.LinkFailure;
239}236}
...@@ -693,8 +690,7 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc...@@ -693,8 +690,7 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
693 const buffer = try gpa.alloc(u8, needed_size);690 const buffer = try gpa.alloc(u8, needed_size);
694 defer gpa.free(buffer);691 defer gpa.free(buffer);
695692
696 var stream = std.io.fixedBufferStream(buffer);693 var writer: Writer = .fixed(buffer);
697 const writer = stream.writer();
698694
699 var ncmds: usize = 0;695 var ncmds: usize = 0;
700696
...@@ -702,43 +698,43 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc...@@ -702,43 +698,43 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
702 {698 {
703 assert(macho_file.segments.items.len == 1);699 assert(macho_file.segments.items.len == 1);
704 const seg = macho_file.segments.items[0];700 const seg = macho_file.segments.items[0];
705 writer.writeStruct(seg) catch |err| switch (err) {701 writer.writeStruct(seg, .little) catch |err| switch (err) {
706 error.NoSpaceLeft => unreachable,702 error.WriteFailed => unreachable,
707 };703 };
708 for (macho_file.sections.items(.header)) |header| {704 for (macho_file.sections.items(.header)) |header| {
709 writer.writeStruct(header) catch |err| switch (err) {705 writer.writeStruct(header, .little) catch |err| switch (err) {
710 error.NoSpaceLeft => unreachable,706 error.WriteFailed => unreachable,
711 };707 };
712 }708 }
713 ncmds += 1;709 ncmds += 1;
714 }710 }
715711
716 writer.writeStruct(macho_file.data_in_code_cmd) catch |err| switch (err) {712 writer.writeStruct(macho_file.data_in_code_cmd, .little) catch |err| switch (err) {
717 error.NoSpaceLeft => unreachable,713 error.WriteFailed => unreachable,
718 };714 };
719 ncmds += 1;715 ncmds += 1;
720 writer.writeStruct(macho_file.symtab_cmd) catch |err| switch (err) {716 writer.writeStruct(macho_file.symtab_cmd, .little) catch |err| switch (err) {
721 error.NoSpaceLeft => unreachable,717 error.WriteFailed => unreachable,
722 };718 };
723 ncmds += 1;719 ncmds += 1;
724 writer.writeStruct(macho_file.dysymtab_cmd) catch |err| switch (err) {720 writer.writeStruct(macho_file.dysymtab_cmd, .little) catch |err| switch (err) {
725 error.NoSpaceLeft => unreachable,721 error.WriteFailed => unreachable,
726 };722 };
727 ncmds += 1;723 ncmds += 1;
728724
729 if (macho_file.platform.isBuildVersionCompatible()) {725 if (macho_file.platform.isBuildVersionCompatible()) {
730 load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {726 load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, &writer) catch |err| switch (err) {
731 error.NoSpaceLeft => unreachable,727 error.WriteFailed => unreachable,
732 };728 };
733 ncmds += 1;729 ncmds += 1;
734 } else {730 } else {
735 load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {731 load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, &writer) catch |err| switch (err) {
736 error.NoSpaceLeft => unreachable,732 error.WriteFailed => unreachable,
737 };733 };
738 ncmds += 1;734 ncmds += 1;
739 }735 }
740736
741 assert(stream.pos == needed_size);737 assert(writer.end == needed_size);
742738
743 try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));739 try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
744740
src/link/MachO/synthetic.zig+12-12
...@@ -27,7 +27,7 @@ pub const GotSection = struct {...@@ -27,7 +27,7 @@ pub const GotSection = struct {
27 return got.symbols.items.len * @sizeOf(u64);27 return got.symbols.items.len * @sizeOf(u64);
28 }28 }
2929
30 pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void {30 pub fn write(got: GotSection, macho_file: *MachO, writer: *Writer) !void {
31 const tracy = trace(@src());31 const tracy = trace(@src());
32 defer tracy.end();32 defer tracy.end();
33 for (got.symbols.items) |ref| {33 for (got.symbols.items) |ref| {
...@@ -89,7 +89,7 @@ pub const StubsSection = struct {...@@ -89,7 +89,7 @@ pub const StubsSection = struct {
89 return stubs.symbols.items.len * header.reserved2;89 return stubs.symbols.items.len * header.reserved2;
90 }90 }
9191
92 pub fn write(stubs: StubsSection, macho_file: *MachO, writer: anytype) !void {92 pub fn write(stubs: StubsSection, macho_file: *MachO, writer: *Writer) !void {
93 const tracy = trace(@src());93 const tracy = trace(@src());
94 defer tracy.end();94 defer tracy.end();
95 const cpu_arch = macho_file.getTarget().cpu.arch;95 const cpu_arch = macho_file.getTarget().cpu.arch;
...@@ -174,7 +174,7 @@ pub const StubsHelperSection = struct {...@@ -174,7 +174,7 @@ pub const StubsHelperSection = struct {
174 return s;174 return s;
175 }175 }
176176
177 pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {177 pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: *Writer) !void {
178 const tracy = trace(@src());178 const tracy = trace(@src());
179 defer tracy.end();179 defer tracy.end();
180180
...@@ -217,7 +217,7 @@ pub const StubsHelperSection = struct {...@@ -217,7 +217,7 @@ pub const StubsHelperSection = struct {
217 }217 }
218 }218 }
219219
220 fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {220 fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: *Writer) !void {
221 _ = stubs_helper;221 _ = stubs_helper;
222 const obj = macho_file.getInternalObject().?;222 const obj = macho_file.getInternalObject().?;
223 const cpu_arch = macho_file.getTarget().cpu.arch;223 const cpu_arch = macho_file.getTarget().cpu.arch;
...@@ -273,7 +273,7 @@ pub const LaSymbolPtrSection = struct {...@@ -273,7 +273,7 @@ pub const LaSymbolPtrSection = struct {
273 return macho_file.stubs.symbols.items.len * @sizeOf(u64);273 return macho_file.stubs.symbols.items.len * @sizeOf(u64);
274 }274 }
275275
276 pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void {276 pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: *Writer) !void {
277 const tracy = trace(@src());277 const tracy = trace(@src());
278 defer tracy.end();278 defer tracy.end();
279 _ = laptr;279 _ = laptr;
...@@ -323,7 +323,7 @@ pub const TlvPtrSection = struct {...@@ -323,7 +323,7 @@ pub const TlvPtrSection = struct {
323 return tlv.symbols.items.len * @sizeOf(u64);323 return tlv.symbols.items.len * @sizeOf(u64);
324 }324 }
325325
326 pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void {326 pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: *Writer) !void {
327 const tracy = trace(@src());327 const tracy = trace(@src());
328 defer tracy.end();328 defer tracy.end();
329329
...@@ -394,7 +394,7 @@ pub const ObjcStubsSection = struct {...@@ -394,7 +394,7 @@ pub const ObjcStubsSection = struct {
394 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);394 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
395 }395 }
396396
397 pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: anytype) !void {397 pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: *Writer) !void {
398 const tracy = trace(@src());398 const tracy = trace(@src());
399 defer tracy.end();399 defer tracy.end();
400400
...@@ -487,7 +487,7 @@ pub const Indsymtab = struct {...@@ -487,7 +487,7 @@ pub const Indsymtab = struct {
487 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);487 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
488 }488 }
489489
490 pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void {490 pub fn write(ind: Indsymtab, macho_file: *MachO, writer: *Writer) !void {
491 const tracy = trace(@src());491 const tracy = trace(@src());
492 defer tracy.end();492 defer tracy.end();
493493
...@@ -564,7 +564,7 @@ pub const DataInCode = struct {...@@ -564,7 +564,7 @@ pub const DataInCode = struct {
564 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;564 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;
565 }565 }
566566
567 pub fn write(dice: DataInCode, macho_file: *MachO, writer: anytype) !void {567 pub fn write(dice: DataInCode, macho_file: *MachO, writer: *Writer) !void {
568 const base_address = if (!macho_file.base.isRelocatable())568 const base_address = if (!macho_file.base.isRelocatable())
569 macho_file.getTextSegment().vmaddr569 macho_file.getTextSegment().vmaddr
570 else570 else
...@@ -572,11 +572,11 @@ pub const DataInCode = struct {...@@ -572,11 +572,11 @@ pub const DataInCode = struct {
572 for (dice.entries.items) |entry| {572 for (dice.entries.items) |entry| {
573 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);573 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);
574 const offset = atom_address + entry.offset - base_address;574 const offset = atom_address + entry.offset - base_address;
575 try writer.writeStruct(macho.data_in_code_entry{575 try writer.writeStruct(@as(macho.data_in_code_entry, .{
576 .offset = @intCast(offset),576 .offset = @intCast(offset),
577 .length = entry.length,577 .length = entry.length,
578 .kind = entry.kind,578 .kind = entry.kind,
579 });579 }), .little);
580 }580 }
581 }581 }
582582
...@@ -594,7 +594,7 @@ const assert = std.debug.assert;...@@ -594,7 +594,7 @@ const assert = std.debug.assert;
594const macho = std.macho;594const macho = std.macho;
595const math = std.math;595const math = std.math;
596const Allocator = std.mem.Allocator;596const Allocator = std.mem.Allocator;
597const Writer = std.io.Writer;597const Writer = std.Io.Writer;
598598
599const trace = @import("../../tracy.zig").trace;599const trace = @import("../../tracy.zig").trace;
600const MachO = @import("../MachO.zig");600const MachO = @import("../MachO.zig");