Commit cc931660eb

Andrew Kelley <andrew@ziglang.org>
2025-08-17 04:32:05
link.MachO: update to not use GenericWriter
1 parent 2dc6ddd
lib/std/Io/Writer.zig
@@ -2381,6 +2381,7 @@ pub fn fromArrayList(array_list: *ArrayList(u8)) Writer {
         .vtable = &.{
             .drain = fixedDrain,
             .flush = noopFlush,
+            .rebase = failingRebase,
         },
         .buffer = array_list.allocatedSlice(),
         .end = array_list.items.len,
lib/std/macho.zig
@@ -1883,10 +1883,8 @@ pub const GenericBlob = extern struct {
 pub const data_in_code_entry = extern struct {
     /// From mach_header to start of data range.
     offset: u32,
-
     /// Number of bytes in data range.
     length: u16,
-
     /// A DICE_KIND value.
     kind: u16,
 };
src/link/MachO/dyld_info/bind.zig
@@ -132,12 +132,14 @@ pub const Bind = struct {
     fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
         if (self.entries.items.len == 0) return;
 
-        const writer = self.buffer.writer(gpa);
-
         log.debug("bind opcodes", .{});
 
         std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
 
+        var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &self.buffer);
+        defer self.buffer = allocating.toArrayList();
+        const writer = &allocating.writer;
+
         var start: usize = 0;
         var seg_id: ?u8 = null;
         for (self.entries.items, 0..) |entry, i| {
@@ -151,7 +153,7 @@ pub const Bind = struct {
         try done(writer);
     }
 
-    fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {
+    fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: *std.Io.Writer) !void {
         if (entries.len == 0) return;
 
         const seg_id = entries[0].segment_id;
@@ -263,7 +265,7 @@ pub const Bind = struct {
         }
     }
 
-    pub fn write(self: Self, writer: anytype) !void {
+    pub fn write(self: Self, writer: *std.Io.Writer) !void {
         try writer.writeAll(self.buffer.items);
     }
 };
@@ -385,12 +387,14 @@ pub const WeakBind = struct {
     fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
         if (self.entries.items.len == 0) return;
 
-        const writer = self.buffer.writer(gpa);
-
         log.debug("weak bind opcodes", .{});
 
         std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
 
+        var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &self.buffer);
+        defer self.buffer = allocating.toArrayList();
+        const writer = &allocating.writer;
+
         var start: usize = 0;
         var seg_id: ?u8 = null;
         for (self.entries.items, 0..) |entry, i| {
@@ -404,7 +408,7 @@ pub const WeakBind = struct {
         try done(writer);
     }
 
-    fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {
+    fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: *std.Io.Writer) !void {
         if (entries.len == 0) return;
 
         const seg_id = entries[0].segment_id;
@@ -505,7 +509,7 @@ pub const WeakBind = struct {
         }
     }
 
-    pub fn write(self: Self, writer: anytype) !void {
+    pub fn write(self: Self, writer: *std.Io.Writer) !void {
         try writer.writeAll(self.buffer.items);
     }
 };
@@ -555,8 +559,6 @@ pub const LazyBind = struct {
     fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
         try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);
 
-        const writer = self.buffer.writer(gpa);
-
         log.debug("lazy bind opcodes", .{});
 
         var addend: i64 = 0;
@@ -578,6 +580,9 @@ pub const LazyBind = struct {
                 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
             };
 
+            var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &self.buffer);
+            defer self.buffer = allocating.toArrayList();
+            const writer = &allocating.writer;
             try setSegmentOffset(entry.segment_id, entry.offset, writer);
             try setSymbol(name, flags, writer);
             try setDylibOrdinal(ordinal, writer);
@@ -592,30 +597,30 @@ pub const LazyBind = struct {
         }
     }
 
-    pub fn write(self: Self, writer: anytype) !void {
+    pub fn write(self: Self, writer: *std.Io.Writer) !void {
         try writer.writeAll(self.buffer.items);
     }
 };
 
-fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
+fn setSegmentOffset(segment_id: u8, offset: u64, writer: *std.Io.Writer) !void {
     log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
     try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
     try std.leb.writeUleb128(writer, offset);
 }
 
-fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void {
+fn setSymbol(name: []const u8, flags: u8, writer: *std.Io.Writer) !void {
     log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });
     try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags)));
     try writer.writeAll(name);
     try writer.writeByte(0);
 }
 
-fn setTypePointer(writer: anytype) !void {
+fn setTypePointer(writer: *std.Io.Writer) !void {
     log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});
     try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER)));
 }
 
-fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {
+fn setDylibOrdinal(ordinal: i16, writer: *std.Io.Writer) !void {
     if (ordinal <= 0) {
         switch (ordinal) {
             macho.BIND_SPECIAL_DYLIB_SELF,
@@ -639,18 +644,18 @@ fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {
     }
 }
 
-fn setAddend(addend: i64, writer: anytype) !void {
+fn setAddend(addend: i64, writer: *std.Io.Writer) !void {
     log.debug(">>> set addend: {x}", .{addend});
     try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
     try std.leb.writeIleb128(writer, addend);
 }
 
-fn doBind(writer: anytype) !void {
+fn doBind(writer: *std.Io.Writer) !void {
     log.debug(">>> bind", .{});
     try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
 }
 
-fn doBindAddAddr(addr: u64, writer: anytype) !void {
+fn doBindAddAddr(addr: u64, writer: *std.Io.Writer) !void {
     log.debug(">>> bind with add: {x}", .{addr});
     if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {
         const imm = @divExact(addr, @sizeOf(u64));
@@ -665,20 +670,20 @@ fn doBindAddAddr(addr: u64, writer: anytype) !void {
     try std.leb.writeUleb128(writer, addr);
 }
 
-fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void {
+fn doBindTimesSkip(count: usize, skip: u64, writer: *std.Io.Writer) !void {
     log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });
     try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
     try std.leb.writeUleb128(writer, count);
     try std.leb.writeUleb128(writer, skip);
 }
 
-fn addAddr(addr: u64, writer: anytype) !void {
+fn addAddr(addr: u64, writer: *std.Io.Writer) !void {
     log.debug(">>> add: {x}", .{addr});
     try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
     try std.leb.writeUleb128(writer, addr);
 }
 
-fn done(writer: anytype) !void {
+fn done(writer: *std.Io.Writer) !void {
     log.debug(">>> done", .{});
     try writer.writeByte(macho.BIND_OPCODE_DONE);
 }
src/link/MachO/dyld_info/Rebase.zig
@@ -110,12 +110,14 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
 fn finalize(rebase: *Rebase, gpa: Allocator) !void {
     if (rebase.entries.items.len == 0) return;
 
-    const writer = rebase.buffer.writer(gpa);
-
     log.debug("rebase opcodes", .{});
 
     std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);
 
+    var allocating: std.Io.Writer.Allocating = .fromArrayList(gpa, &rebase.buffer);
+    defer rebase.buffer = allocating.toArrayList();
+    const writer = &allocating.writer;
+
     try setTypePointer(writer);
 
     var start: usize = 0;
src/link/MachO/dyld_info/Trie.zig
@@ -170,8 +170,13 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
     }
 
     try self.buffer.ensureTotalCapacityPrecise(allocator, size);
+
+    var allocating: std.Io.Writer.Allocating = .fromArrayList(allocator, &self.buffer);
+    defer self.buffer = allocating.toArrayList();
+    const writer = &allocating.writer;
+
     for (ordered_nodes.items) |node_index| {
-        try self.writeNode(node_index, self.buffer.writer(allocator));
+        try self.writeNode(node_index, writer);
     }
 }
 
@@ -232,7 +237,7 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {
     self.buffer.deinit(allocator);
 }
 
-pub fn write(self: Trie, writer: anytype) !void {
+pub fn write(self: Trie, writer: *std.Io.Writer) !void {
     if (self.buffer.items.len == 0) return;
     try writer.writeAll(self.buffer.items);
 }
@@ -243,7 +248,7 @@ pub fn write(self: Trie, writer: anytype) !void {
 /// iterate over `Trie.ordered_nodes` and call this method on each node.
 /// This is one of the requirements of the MachO.
 /// Panics if `finalize` was not called before calling this method.
-fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
+fn writeNode(self: *Trie, node_index: Node.Index, writer: *std.Io.Writer) !void {
     const slice = self.nodes.slice();
     const edges = slice.items(.edges)[node_index];
     const is_terminal = slice.items(.is_terminal)[node_index];
@@ -253,21 +258,21 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
     if (is_terminal) {
         // Terminal node info: encode export flags and vmaddr offset of this symbol.
         var info_buf: [@sizeOf(u64) * 2]u8 = undefined;
-        var info_stream = std.io.fixedBufferStream(&info_buf);
+        var info_stream: std.Io.Writer = .fixed(&info_buf);
         // TODO Implement for special flags.
         assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
             export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
-        try leb.writeUleb128(info_stream.writer(), export_flags);
-        try leb.writeUleb128(info_stream.writer(), vmaddr_offset);
+        try leb.writeUleb128(&info_stream, export_flags);
+        try leb.writeUleb128(&info_stream, vmaddr_offset);
 
         // Encode the size of the terminal node info.
         var size_buf: [@sizeOf(u64)]u8 = undefined;
-        var size_stream = std.io.fixedBufferStream(&size_buf);
-        try leb.writeUleb128(size_stream.writer(), info_stream.pos);
+        var size_stream: std.Io.Writer = .fixed(&size_buf);
+        try leb.writeUleb128(&size_stream, info_stream.end);
 
         // Now, write them to the output stream.
-        try writer.writeAll(size_buf[0..size_stream.pos]);
-        try writer.writeAll(info_buf[0..info_stream.pos]);
+        try writer.writeAll(size_buf[0..size_stream.end]);
+        try writer.writeAll(info_buf[0..info_stream.end]);
     } else {
         // Non-terminal node is delimited by 0 byte.
         try writer.writeByte(0);
src/link/MachO/Archive.zig
@@ -81,34 +81,20 @@ pub fn writeHeader(
     object_name: []const u8,
     object_size: usize,
     format: Format,
-    writer: anytype,
+    writer: *Writer,
 ) !void {
-    var hdr: ar_hdr = .{
-        .ar_name = undefined,
-        .ar_date = undefined,
-        .ar_uid = undefined,
-        .ar_gid = undefined,
-        .ar_mode = undefined,
-        .ar_size = undefined,
-        .ar_fmag = undefined,
-    };
-    @memset(mem.asBytes(&hdr), 0x20);
-    inline for (@typeInfo(ar_hdr).@"struct".fields) |field| {
-        var stream = std.io.fixedBufferStream(&@field(hdr, field.name));
-        stream.writer().print("0", .{}) catch unreachable;
-    }
-    @memcpy(&hdr.ar_fmag, ARFMAG);
+    var hdr: ar_hdr = .{};
 
     const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format));
     const total_object_size = object_size + object_name_len;
 
     {
-        var stream = std.io.fixedBufferStream(&hdr.ar_name);
-        stream.writer().print("#1/{d}", .{object_name_len}) catch unreachable;
+        var stream: Writer = .fixed(&hdr.ar_name);
+        stream.print("#1/{d}", .{object_name_len}) catch unreachable;
     }
     {
-        var stream = std.io.fixedBufferStream(&hdr.ar_size);
-        stream.writer().print("{d}", .{total_object_size}) catch unreachable;
+        var stream: Writer = .fixed(&hdr.ar_size);
+        stream.print("{d}", .{total_object_size}) catch unreachable;
     }
 
     try writer.writeAll(mem.asBytes(&hdr));
@@ -116,7 +102,7 @@ pub fn writeHeader(
 
     const padding = object_name_len - object_name.len - 1;
     if (padding > 0) {
-        try writer.writeByteNTimes(0, padding);
+        try writer.splatByteAll(0, padding);
     }
 }
 
@@ -138,25 +124,19 @@ pub const SYMDEF64_SORTED = "__.SYMDEF_64 SORTED";
 
 pub const ar_hdr = extern struct {
     /// Member file name, sometimes / terminated.
-    ar_name: [16]u8,
-
+    ar_name: [16]u8 = "0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20".*,
     /// File date, decimal seconds since Epoch.
-    ar_date: [12]u8,
-
+    ar_date: [12]u8 = "0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20".*,
     /// User ID, in ASCII format.
-    ar_uid: [6]u8,
-
+    ar_uid: [6]u8 = "0\x20\x20\x20\x20\x20".*,
     /// Group ID, in ASCII format.
-    ar_gid: [6]u8,
-
+    ar_gid: [6]u8 = "0\x20\x20\x20\x20\x20".*,
     /// File mode, in ASCII octal.
-    ar_mode: [8]u8,
-
+    ar_mode: [8]u8 = "0\x20\x20\x20\x20\x20\x20\x20".*,
     /// File size, in ASCII decimal.
-    ar_size: [10]u8,
-
+    ar_size: [10]u8 = "0\x20\x20\x20\x20\x20\x20\x20\x20\x20".*,
     /// Always contains ARFMAG.
-    ar_fmag: [2]u8,
+    ar_fmag: [2]u8 = ARFMAG.*,
 
     fn date(self: ar_hdr) !u64 {
         const value = mem.trimEnd(u8, &self.ar_date, &[_]u8{@as(u8, 0x20)});
@@ -201,7 +181,7 @@ pub const ArSymtab = struct {
         return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
     }
 
-    pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: anytype) !void {
+    pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: *Writer) !void {
         const ptr_width = ptrWidth(format);
         // Header
         try writeHeader(SYMDEF, ar.size(format), format, writer);
@@ -226,7 +206,7 @@ pub const ArSymtab = struct {
         // Strtab
         try writer.writeAll(ar.strtab.buffer.items);
         if (padding > 0) {
-            try writer.writeByteNTimes(0, padding);
+            try writer.splatByteAll(0, padding);
         }
     }
 
@@ -275,7 +255,7 @@ pub fn ptrWidth(format: Format) usize {
     };
 }
 
-pub fn writeInt(format: Format, value: u64, writer: anytype) !void {
+pub fn writeInt(format: Format, value: u64, writer: *Writer) !void {
     switch (format) {
         .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
         .p64 => try writer.writeInt(u64, value, .little),
@@ -299,7 +279,7 @@ const mem = std.mem;
 const std = @import("std");
 const Allocator = std.mem.Allocator;
 const Path = std.Build.Cache.Path;
-const Writer = std.io.Writer;
+const Writer = std.Io.Writer;
 
 const Archive = @This();
 const File = @import("file.zig").File;
src/link/MachO/Atom.zig
@@ -581,7 +581,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
     relocs_log.debug("{x}: {s}", .{ self.value, name });
 
     var has_error = false;
-    var stream = std.io.fixedBufferStream(buffer);
+    var stream: Writer = .fixed(buffer);
     var i: usize = 0;
     while (i < relocs.len) : (i += 1) {
         const rel = relocs[i];
@@ -592,8 +592,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
             if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;
         }
 
-        try stream.seekTo(rel_offset);
-        self.resolveRelocInner(rel, subtractor, buffer, macho_file, stream.writer()) catch |err| {
+        stream.end = rel_offset;
+        self.resolveRelocInner(rel, subtractor, buffer, macho_file, &stream) catch |err| {
             switch (err) {
                 error.RelaxFail => {
                     const target = switch (rel.tag) {
@@ -630,6 +630,7 @@ const ResolveError = error{
     UnexpectedRemainder,
     Overflow,
     OutOfMemory,
+    WriteFailed,
 };
 
 fn resolveRelocInner(
@@ -638,7 +639,7 @@ fn resolveRelocInner(
     subtractor: ?Relocation,
     code: []u8,
     macho_file: *MachO,
-    writer: anytype,
+    writer: *Writer,
 ) ResolveError!void {
     const t = &macho_file.base.comp.root_mod.resolved_target.result;
     const cpu_arch = t.cpu.arch;
@@ -1147,7 +1148,7 @@ const math = std.math;
 const mem = std.mem;
 const log = std.log.scoped(.link);
 const relocs_log = std.log.scoped(.link_relocs);
-const Writer = std.io.Writer;
+const Writer = std.Io.Writer;
 const Allocator = mem.Allocator;
 const AtomicBool = std.atomic.Value(bool);
 
src/link/MachO/CodeSignature.zig
@@ -304,10 +304,10 @@ pub fn writeAdhocSignature(
     var hash: [hash_size]u8 = undefined;
 
     if (self.requirements) |*req| {
-        var buf = std.array_list.Managed(u8).init(allocator);
-        defer buf.deinit();
-        try req.write(buf.writer());
-        Sha256.hash(buf.items, &hash, .{});
+        var a: std.Io.Writer.Allocating = .init(allocator);
+        defer a.deinit();
+        try req.write(&a.writer);
+        Sha256.hash(a.written(), &hash, .{});
         self.code_directory.addSpecialHash(req.slotType(), hash);
 
         try blobs.append(.{ .requirements = req });
@@ -316,10 +316,10 @@ pub fn writeAdhocSignature(
     }
 
     if (self.entitlements) |*ents| {
-        var buf = std.array_list.Managed(u8).init(allocator);
-        defer buf.deinit();
-        try ents.write(buf.writer());
-        Sha256.hash(buf.items, &hash, .{});
+        var a: std.Io.Writer.Allocating = .init(allocator);
+        defer a.deinit();
+        try ents.write(&a.writer);
+        Sha256.hash(a.written(), &hash, .{});
         self.code_directory.addSpecialHash(ents.slotType(), hash);
 
         try blobs.append(.{ .entitlements = ents });
src/link/MachO/DebugSymbols.zig
@@ -273,14 +273,13 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
     const buffer = try gpa.alloc(u8, needed_size);
     defer gpa.free(buffer);
 
-    var stream = std.io.fixedBufferStream(buffer);
-    const writer = stream.writer();
+    var writer: Writer = .fixed(buffer);
 
     var ncmds: usize = 0;
 
     // UUID comes first presumably to speed up lookup by the consumer like lldb.
     @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);
-    try writer.writeStruct(self.uuid_cmd);
+    try writer.writeStruct(self.uuid_cmd, .little);
     ncmds += 1;
 
     // Segment and section load commands
@@ -293,11 +292,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
             var out_seg = seg;
             out_seg.fileoff = 0;
             out_seg.filesize = 0;
-            try writer.writeStruct(out_seg);
+            try writer.writeStruct(out_seg, .little);
             for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
                 var out_header = header;
                 out_header.offset = 0;
-                try writer.writeStruct(out_header);
+                try writer.writeStruct(out_header, .little);
             }
             sect_id += seg.nsects;
         }
@@ -306,19 +305,19 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
         // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
         sect_id = 0;
         for (self.segments.items) |seg| {
-            try writer.writeStruct(seg);
+            try writer.writeStruct(seg, .little);
             for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
-                try writer.writeStruct(header);
+                try writer.writeStruct(header, .little);
             }
             sect_id += seg.nsects;
         }
         ncmds += self.segments.items.len;
     }
 
-    try writer.writeStruct(self.symtab_cmd);
+    try writer.writeStruct(self.symtab_cmd, .little);
     ncmds += 1;
 
-    assert(stream.pos == needed_size);
+    assert(writer.end == needed_size);
 
     try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
 
@@ -460,7 +459,7 @@ const math = std.math;
 const mem = std.mem;
 const padToIdeal = MachO.padToIdeal;
 const trace = @import("../../tracy.zig").trace;
-const Writer = std.io.Writer;
+const Writer = std.Io.Writer;
 
 const Allocator = mem.Allocator;
 const MachO = @import("../MachO.zig");
src/link/MachO/InternalObject.zig
@@ -261,7 +261,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
 
     sect.offset = @intCast(self.objc_methnames.items.len);
     try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);
-    self.objc_methnames.writer(gpa).print("{s}\x00", .{methname}) catch unreachable;
+    self.objc_methnames.print(gpa, "{s}\x00", .{methname}) catch unreachable;
 
     const name_str = try self.addString(gpa, "ltmp");
     const sym_index = try self.addSymbol(gpa);
src/link/MachO/load_commands.zig
@@ -3,9 +3,9 @@ const assert = std.debug.assert;
 const log = std.log.scoped(.link);
 const macho = std.macho;
 const mem = std.mem;
-const Writer = std.io.Writer;
+const Writer = std.Io.Writer;
+const Allocator = std.mem.Allocator;
 
-const Allocator = mem.Allocator;
 const DebugSymbols = @import("DebugSymbols.zig");
 const Dylib = @import("Dylib.zig");
 const MachO = @import("../MachO.zig");
@@ -181,22 +181,22 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
     return offset;
 }
 
-pub fn writeDylinkerLC(writer: anytype) !void {
+pub fn writeDylinkerLC(writer: *Writer) !void {
     const name_len = mem.sliceTo(default_dyld_path, 0).len;
     const cmdsize = @as(u32, @intCast(mem.alignForward(
         u64,
         @sizeOf(macho.dylinker_command) + name_len,
         @sizeOf(u64),
     )));
-    try writer.writeStruct(macho.dylinker_command{
+    try writer.writeStruct(@as(macho.dylinker_command, .{
         .cmd = .LOAD_DYLINKER,
         .cmdsize = cmdsize,
         .name = @sizeOf(macho.dylinker_command),
-    });
+    }), .little);
     try writer.writeAll(mem.sliceTo(default_dyld_path, 0));
     const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;
     if (padding > 0) {
-        try writer.writeByteNTimes(0, padding);
+        try writer.splatByteAll(0, padding);
     }
 }
 
@@ -208,14 +208,14 @@ const WriteDylibLCCtx = struct {
     compatibility_version: u32 = 0x10000,
 };
 
-pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
+pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: *Writer) !void {
     const name_len = ctx.name.len + 1;
     const cmdsize = @as(u32, @intCast(mem.alignForward(
         u64,
         @sizeOf(macho.dylib_command) + name_len,
         @sizeOf(u64),
     )));
-    try writer.writeStruct(macho.dylib_command{
+    try writer.writeStruct(@as(macho.dylib_command, .{
         .cmd = ctx.cmd,
         .cmdsize = cmdsize,
         .dylib = .{
@@ -224,16 +224,16 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
             .current_version = ctx.current_version,
             .compatibility_version = ctx.compatibility_version,
         },
-    });
+    }), .little);
     try writer.writeAll(ctx.name);
     try writer.writeByte(0);
     const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;
     if (padding > 0) {
-        try writer.writeByteNTimes(0, padding);
+        try writer.splatByteAll(0, padding);
     }
 }
 
-pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
+pub fn writeDylibIdLC(macho_file: *MachO, writer: *Writer) !void {
     const comp = macho_file.base.comp;
     const gpa = comp.gpa;
     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 {
     }, writer);
 }
 
-pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {
+pub fn writeRpathLC(rpath: []const u8, writer: *Writer) !void {
     const rpath_len = rpath.len + 1;
     const cmdsize = @as(u32, @intCast(mem.alignForward(
         u64,
         @sizeOf(macho.rpath_command) + rpath_len,
         @sizeOf(u64),
     )));
-    try writer.writeStruct(macho.rpath_command{
+    try writer.writeStruct(@as(macho.rpath_command, .{
         .cmdsize = cmdsize,
         .path = @sizeOf(macho.rpath_command),
-    });
+    }), .little);
     try writer.writeAll(rpath);
     try writer.writeByte(0);
     const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
     if (padding > 0) {
-        try writer.writeByteNTimes(0, padding);
+        try writer.splatByteAll(0, padding);
     }
 }
 
-pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {
+pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: *Writer) !void {
     const cmd: macho.LC = switch (platform.os_tag) {
         .macos => .VERSION_MIN_MACOSX,
         .ios => .VERSION_MIN_IPHONEOS,
@@ -296,9 +296,9 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer
     }));
 }
 
-pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {
+pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: *Writer) !void {
     const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
-    try writer.writeStruct(macho.build_version_command{
+    try writer.writeStruct(@as(macho.build_version_command, .{
         .cmdsize = cmdsize,
         .platform = platform.toApplePlatform(),
         .minos = platform.toAppleVersion(),
@@ -307,7 +307,7 @@ pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticV
         else
             platform.toAppleVersion(),
         .ntools = 1,
-    });
+    }), .little);
     try writer.writeAll(mem.asBytes(&macho.build_tool_version{
         .tool = .ZIG,
         .version = 0x0,
src/link/MachO/relocatable.zig
@@ -205,35 +205,32 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
         state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
     }
 
-    var buffer = std.array_list.Managed(u8).init(gpa);
-    defer buffer.deinit();
-    try buffer.ensureTotalCapacityPrecise(total_size);
-    const writer = buffer.writer();
+    const buffer = try gpa.alloc(u8, total_size);
+    defer gpa.free(buffer);
+    var writer: Writer = .fixed(buffer);
 
     // Write magic
-    try writer.writeAll(Archive.ARMAG);
+    writer.writeAll(Archive.ARMAG) catch unreachable;
 
     // Write symtab
-    ar_symtab.write(format, macho_file, writer) catch |err| switch (err) {
-        error.OutOfMemory => return error.OutOfMemory,
-        else => |e| return diags.fail("failed to write archive symbol table: {s}", .{@errorName(e)}),
-    };
+    ar_symtab.write(format, macho_file, &writer) catch |err|
+        return diags.fail("failed to write archive symbol table: {t}", .{err});
 
     // Write object files
     for (files.items) |index| {
-        const aligned = mem.alignForward(usize, buffer.items.len, 2);
-        const padding = aligned - buffer.items.len;
+        const aligned = mem.alignForward(usize, writer.end, 2);
+        const padding = aligned - writer.end;
         if (padding > 0) {
-            try writer.writeByteNTimes(0, padding);
+            writer.splatByteAll(0, padding) catch unreachable;
         }
-        macho_file.getFile(index).?.writeAr(format, macho_file, writer) catch |err|
-            return diags.fail("failed to write archive: {s}", .{@errorName(err)});
+        macho_file.getFile(index).?.writeAr(format, macho_file, &writer) catch |err|
+            return diags.fail("failed to write archive: {t}", .{err});
     }
 
-    assert(buffer.items.len == total_size);
+    assert(writer.end == total_size);
 
     try macho_file.setEndPos(total_size);
-    try macho_file.pwriteAll(buffer.items, 0);
+    try macho_file.pwriteAll(writer.buffered(), 0);
 
     if (diags.hasErrors()) return error.LinkFailure;
 }
@@ -693,8 +690,7 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
     const buffer = try gpa.alloc(u8, needed_size);
     defer gpa.free(buffer);
 
-    var stream = std.io.fixedBufferStream(buffer);
-    const writer = stream.writer();
+    var writer: Writer = .fixed(buffer);
 
     var ncmds: usize = 0;
 
@@ -702,43 +698,43 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
     {
         assert(macho_file.segments.items.len == 1);
         const seg = macho_file.segments.items[0];
-        writer.writeStruct(seg) catch |err| switch (err) {
-            error.NoSpaceLeft => unreachable,
+        writer.writeStruct(seg, .little) catch |err| switch (err) {
+            error.WriteFailed => unreachable,
         };
         for (macho_file.sections.items(.header)) |header| {
-            writer.writeStruct(header) catch |err| switch (err) {
-                error.NoSpaceLeft => unreachable,
+            writer.writeStruct(header, .little) catch |err| switch (err) {
+                error.WriteFailed => unreachable,
             };
         }
         ncmds += 1;
     }
 
-    writer.writeStruct(macho_file.data_in_code_cmd) catch |err| switch (err) {
-        error.NoSpaceLeft => unreachable,
+    writer.writeStruct(macho_file.data_in_code_cmd, .little) catch |err| switch (err) {
+        error.WriteFailed => unreachable,
     };
     ncmds += 1;
-    writer.writeStruct(macho_file.symtab_cmd) catch |err| switch (err) {
-        error.NoSpaceLeft => unreachable,
+    writer.writeStruct(macho_file.symtab_cmd, .little) catch |err| switch (err) {
+        error.WriteFailed => unreachable,
     };
     ncmds += 1;
-    writer.writeStruct(macho_file.dysymtab_cmd) catch |err| switch (err) {
-        error.NoSpaceLeft => unreachable,
+    writer.writeStruct(macho_file.dysymtab_cmd, .little) catch |err| switch (err) {
+        error.WriteFailed => unreachable,
     };
     ncmds += 1;
 
     if (macho_file.platform.isBuildVersionCompatible()) {
-        load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
-            error.NoSpaceLeft => unreachable,
+        load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, &writer) catch |err| switch (err) {
+            error.WriteFailed => unreachable,
         };
         ncmds += 1;
     } else {
-        load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
-            error.NoSpaceLeft => unreachable,
+        load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, &writer) catch |err| switch (err) {
+            error.WriteFailed => unreachable,
         };
         ncmds += 1;
     }
 
-    assert(stream.pos == needed_size);
+    assert(writer.end == needed_size);
 
     try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
 
src/link/MachO/synthetic.zig
@@ -27,7 +27,7 @@ pub const GotSection = struct {
         return got.symbols.items.len * @sizeOf(u64);
     }
 
-    pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void {
+    pub fn write(got: GotSection, macho_file: *MachO, writer: *Writer) !void {
         const tracy = trace(@src());
         defer tracy.end();
         for (got.symbols.items) |ref| {
@@ -89,7 +89,7 @@ pub const StubsSection = struct {
         return stubs.symbols.items.len * header.reserved2;
     }
 
-    pub fn write(stubs: StubsSection, macho_file: *MachO, writer: anytype) !void {
+    pub fn write(stubs: StubsSection, macho_file: *MachO, writer: *Writer) !void {
         const tracy = trace(@src());
         defer tracy.end();
         const cpu_arch = macho_file.getTarget().cpu.arch;
@@ -174,7 +174,7 @@ pub const StubsHelperSection = struct {
         return s;
     }
 
-    pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
+    pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: *Writer) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
@@ -217,7 +217,7 @@ pub const StubsHelperSection = struct {
         }
     }
 
-    fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
+    fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: *Writer) !void {
         _ = stubs_helper;
         const obj = macho_file.getInternalObject().?;
         const cpu_arch = macho_file.getTarget().cpu.arch;
@@ -273,7 +273,7 @@ pub const LaSymbolPtrSection = struct {
         return macho_file.stubs.symbols.items.len * @sizeOf(u64);
     }
 
-    pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void {
+    pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: *Writer) !void {
         const tracy = trace(@src());
         defer tracy.end();
         _ = laptr;
@@ -323,7 +323,7 @@ pub const TlvPtrSection = struct {
         return tlv.symbols.items.len * @sizeOf(u64);
     }
 
-    pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void {
+    pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: *Writer) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
@@ -394,7 +394,7 @@ pub const ObjcStubsSection = struct {
         return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
     }
 
-    pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: anytype) !void {
+    pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: *Writer) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
@@ -487,7 +487,7 @@ pub const Indsymtab = struct {
         macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
     }
 
-    pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void {
+    pub fn write(ind: Indsymtab, macho_file: *MachO, writer: *Writer) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
@@ -564,7 +564,7 @@ pub const DataInCode = struct {
         macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;
     }
 
-    pub fn write(dice: DataInCode, macho_file: *MachO, writer: anytype) !void {
+    pub fn write(dice: DataInCode, macho_file: *MachO, writer: *Writer) !void {
         const base_address = if (!macho_file.base.isRelocatable())
             macho_file.getTextSegment().vmaddr
         else
@@ -572,11 +572,11 @@ pub const DataInCode = struct {
         for (dice.entries.items) |entry| {
             const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);
             const offset = atom_address + entry.offset - base_address;
-            try writer.writeStruct(macho.data_in_code_entry{
+            try writer.writeStruct(@as(macho.data_in_code_entry, .{
                 .offset = @intCast(offset),
                 .length = entry.length,
                 .kind = entry.kind,
-            });
+            }), .little);
         }
     }
 
@@ -594,7 +594,7 @@ const assert = std.debug.assert;
 const macho = std.macho;
 const math = std.math;
 const Allocator = std.mem.Allocator;
-const Writer = std.io.Writer;
+const Writer = std.Io.Writer;
 
 const trace = @import("../../tracy.zig").trace;
 const MachO = @import("../MachO.zig");
src/link/MachO/UnwindInfo.zig
@@ -293,8 +293,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
     const seg = macho_file.getTextSegment();
     const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];
 
-    var stream = std.io.fixedBufferStream(buffer);
-    const writer = stream.writer();
+    var writer: Writer = .fixed(buffer);
 
     const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);
     const common_encodings_count: u32 = info.common_encodings_count;
@@ -303,14 +302,14 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
     const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);
     const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));
 
-    try writer.writeStruct(macho.unwind_info_section_header{
+    try writer.writeStruct(@as(macho.unwind_info_section_header, .{
         .commonEncodingsArraySectionOffset = common_encodings_offset,
         .commonEncodingsArrayCount = common_encodings_count,
         .personalityArraySectionOffset = personalities_offset,
         .personalityArrayCount = personalities_count,
         .indexSectionOffset = indexes_offset,
         .indexCount = indexes_count,
-    });
+    }), .little);
 
     try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));
 
@@ -325,42 +324,42 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
     for (info.pages.items, 0..) |page, i| {
         assert(page.count > 0);
         const rec = info.records.items[page.start].getUnwindRecord(macho_file);
-        try writer.writeStruct(macho.unwind_info_section_header_index_entry{
+        try writer.writeStruct(@as(macho.unwind_info_section_header_index_entry, .{
             .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
             .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
             .lsdaIndexArraySectionOffset = lsda_base_offset +
                 info.lsdas_lookup.items[page.start] * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),
-        });
+        }), .little);
     }
 
     const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);
     const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));
-    try writer.writeStruct(macho.unwind_info_section_header_index_entry{
+    try writer.writeStruct(@as(macho.unwind_info_section_header_index_entry, .{
         .functionOffset = sentinel_address,
         .secondLevelPagesSectionOffset = 0,
         .lsdaIndexArraySectionOffset = lsda_base_offset +
             @as(u32, @intCast(info.lsdas.items.len)) * @sizeOf(macho.unwind_info_section_header_lsda_index_entry),
-    });
+    }), .little);
 
     for (info.lsdas.items) |index| {
         const rec = info.records.items[index].getUnwindRecord(macho_file);
-        try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{
+        try writer.writeStruct(@as(macho.unwind_info_section_header_lsda_index_entry, .{
             .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
             .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),
-        });
+        }), .little);
     }
 
     for (info.pages.items) |page| {
-        const start = stream.pos;
-        try page.write(info, macho_file, writer);
-        const nwritten = stream.pos - start;
+        const start = writer.end;
+        try page.write(info, macho_file, &writer);
+        const nwritten = writer.end - start;
         if (nwritten < second_level_page_bytes) {
             const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;
-            try writer.writeByteNTimes(0, padding);
+            try writer.splatByteAll(0, padding);
         }
     }
 
-    @memset(buffer[stream.pos..], 0);
+    @memset(buffer[writer.end..], 0);
 }
 
 fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {
@@ -611,33 +610,33 @@ const Page = struct {
         } };
     }
 
-    fn write(page: Page, info: UnwindInfo, macho_file: *MachO, writer: anytype) !void {
+    fn write(page: Page, info: UnwindInfo, macho_file: *MachO, writer: *Writer) !void {
         const seg = macho_file.getTextSegment();
 
         switch (page.kind) {
             .regular => {
-                try writer.writeStruct(macho.unwind_info_regular_second_level_page_header{
+                try writer.writeStruct(@as(macho.unwind_info_regular_second_level_page_header, .{
                     .entryPageOffset = @sizeOf(macho.unwind_info_regular_second_level_page_header),
                     .entryCount = page.count,
-                });
+                }), .little);
 
                 for (info.records.items[page.start..][0..page.count]) |ref| {
                     const rec = ref.getUnwindRecord(macho_file);
-                    try writer.writeStruct(macho.unwind_info_regular_second_level_entry{
+                    try writer.writeStruct(@as(macho.unwind_info_regular_second_level_entry, .{
                         .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
                         .encoding = rec.enc.enc,
-                    });
+                    }), .little);
                 }
             },
             .compressed => {
                 const entry_offset = @sizeOf(macho.unwind_info_compressed_second_level_page_header) +
                     @as(u16, @intCast(page.page_encodings_count)) * @sizeOf(u32);
-                try writer.writeStruct(macho.unwind_info_compressed_second_level_page_header{
+                try writer.writeStruct(@as(macho.unwind_info_compressed_second_level_page_header, .{
                     .entryPageOffset = entry_offset,
                     .entryCount = page.count,
                     .encodingsPageOffset = @sizeOf(macho.unwind_info_compressed_second_level_page_header),
                     .encodingsCount = page.page_encodings_count,
-                });
+                }), .little);
 
                 for (page.page_encodings[0..page.page_encodings_count]) |enc| {
                     try writer.writeInt(u32, enc.enc, .little);
@@ -656,7 +655,7 @@ const Page = struct {
                         .funcOffset = @as(u24, @intCast(rec.getAtomAddress(macho_file) - first_rec.getAtomAddress(macho_file))),
                         .encodingIndex = @as(u8, @intCast(enc_index)),
                     };
-                    try writer.writeStruct(compressed);
+                    try writer.writeStruct(compressed, .little);
                 }
             },
         }
@@ -673,7 +672,7 @@ const macho = std.macho;
 const math = std.math;
 const mem = std.mem;
 const trace = @import("../../tracy.zig").trace;
-const Writer = std.io.Writer;
+const Writer = std.Io.Writer;
 
 const Allocator = mem.Allocator;
 const Atom = @import("Atom.zig");
src/link/MachO.zig
@@ -589,7 +589,7 @@ pub fn flush(
     );
 
     const ncmds, const sizeofcmds, const uuid_cmd_offset = self.writeLoadCommands() catch |err| switch (err) {
-        error.NoSpaceLeft => unreachable,
+        error.WriteFailed => unreachable,
         error.OutOfMemory => return error.OutOfMemory,
         error.LinkFailure => return error.LinkFailure,
     };
@@ -1074,7 +1074,7 @@ fn accessLibPath(
 
     for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
         test_path.clearRetainingCapacity();
-        try test_path.writer().print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
+        try test_path.print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
         try checked_paths.append(try arena.dupe(u8, test_path.items));
         fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
             error.FileNotFound => continue,
@@ -1097,7 +1097,7 @@ fn accessFrameworkPath(
 
     for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
         test_path.clearRetainingCapacity();
-        try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
+        try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
             search_dir,
             name,
             name,
@@ -1178,9 +1178,9 @@ fn parseDependentDylibs(self: *MachO) !void {
                     for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
                         test_path.clearRetainingCapacity();
                         if (self.base.comp.sysroot) |root| {
-                            try test_path.writer().print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
+                            try test_path.print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
                         } else {
-                            try test_path.writer().print("{s}{s}", .{ path, ext });
+                            try test_path.print("{s}{s}", .{ path, ext });
                         }
                         try checked_paths.append(try arena.dupe(u8, test_path.items));
                         fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
@@ -2528,8 +2528,8 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
         fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
             const off = try macho_file.cast(usize, th.value);
             const size = th.size();
-            var stream = std.io.fixedBufferStream(buffer[off..][0..size]);
-            try th.write(macho_file, stream.writer());
+            var stream: Writer = .fixed(buffer[off..][0..size]);
+            try th.write(macho_file, &stream);
         }
     }.doWork;
     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 {
 
     const doWork = struct {
         fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {
-            var stream = std.io.fixedBufferStream(buffer);
+            var stream: Writer = .fixed(buffer);
             switch (tag) {
                 .eh_frame => eh_frame.write(macho_file, buffer),
                 .unwind_info => try macho_file.unwind_info.write(macho_file, buffer),
-                .got => try macho_file.got.write(macho_file, stream.writer()),
-                .stubs => try macho_file.stubs.write(macho_file, stream.writer()),
-                .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, stream.writer()),
-                .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, stream.writer()),
-                .objc_stubs => try macho_file.objc_stubs.write(macho_file, stream.writer()),
+                .got => try macho_file.got.write(macho_file, &stream),
+                .stubs => try macho_file.stubs.write(macho_file, &stream),
+                .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, &stream),
+                .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, &stream),
+                .objc_stubs => try macho_file.objc_stubs.write(macho_file, &stream),
             }
         }
     }.doWork;
@@ -2605,8 +2605,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {
             try macho_file.lazy_bind_section.updateSize(macho_file);
             const sect_id = macho_file.stubs_helper_sect_index.?;
             const out = &macho_file.sections.items(.out)[sect_id];
-            var stream = std.io.fixedBufferStream(out.items);
-            try macho_file.stubs_helper.write(macho_file, stream.writer());
+            var stream: Writer = .fixed(out.items);
+            try macho_file.stubs_helper.write(macho_file, &stream);
         }
     }.doWork;
     doWork(self) catch |err|
@@ -2669,18 +2669,17 @@ fn writeDyldInfo(self: *MachO) !void {
     defer gpa.free(buffer);
     @memset(buffer, 0);
 
-    var stream = std.io.fixedBufferStream(buffer);
-    const writer = stream.writer();
-
-    try self.rebase_section.write(writer);
-    try stream.seekTo(cmd.bind_off - base_off);
-    try self.bind_section.write(writer);
-    try stream.seekTo(cmd.weak_bind_off - base_off);
-    try self.weak_bind_section.write(writer);
-    try stream.seekTo(cmd.lazy_bind_off - base_off);
-    try self.lazy_bind_section.write(writer);
-    try stream.seekTo(cmd.export_off - base_off);
-    try self.export_trie.write(writer);
+    var writer: Writer = .fixed(buffer);
+
+    try self.rebase_section.write(&writer);
+    writer.end = cmd.bind_off - base_off;
+    try self.bind_section.write(&writer);
+    writer.end = cmd.weak_bind_off - base_off;
+    try self.weak_bind_section.write(&writer);
+    writer.end = cmd.lazy_bind_off - base_off;
+    try self.lazy_bind_section.write(&writer);
+    writer.end = cmd.export_off - base_off;
+    try self.export_trie.write(&writer);
     try self.pwriteAll(buffer, cmd.rebase_off);
 }
 
@@ -2689,10 +2688,10 @@ pub fn writeDataInCode(self: *MachO) !void {
     defer tracy.end();
     const gpa = self.base.comp.gpa;
     const cmd = self.data_in_code_cmd;
-    var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.data_in_code.size());
+    var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.data_in_code.size());
     defer buffer.deinit();
-    try self.data_in_code.write(self, buffer.writer());
-    try self.pwriteAll(buffer.items, cmd.dataoff);
+    self.data_in_code.write(self, &buffer.writer) catch return error.OutOfMemory;
+    try self.pwriteAll(buffer.written(), cmd.dataoff);
 }
 
 fn writeIndsymtab(self: *MachO) !void {
@@ -2701,10 +2700,11 @@ fn writeIndsymtab(self: *MachO) !void {
     const gpa = self.base.comp.gpa;
     const cmd = self.dysymtab_cmd;
     const needed_size = cmd.nindirectsyms * @sizeOf(u32);
-    var buffer = try std.array_list.Managed(u8).initCapacity(gpa, needed_size);
-    defer buffer.deinit();
-    try self.indsymtab.write(self, buffer.writer());
-    try self.pwriteAll(buffer.items, cmd.indirectsymoff);
+    const buffer = try gpa.alloc(u8, needed_size);
+    defer gpa.free(buffer);
+    var writer: Writer = .fixed(buffer);
+    try self.indsymtab.write(self, &writer);
+    try self.pwriteAll(buffer, cmd.indirectsymoff);
 }
 
 pub fn writeSymtabToFile(self: *MachO) !void {
@@ -2821,8 +2821,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
     const buffer = try gpa.alloc(u8, needed_size);
     defer gpa.free(buffer);
 
-    var stream = std.io.fixedBufferStream(buffer);
-    const writer = stream.writer();
+    var writer: Writer = .fixed(buffer);
 
     var ncmds: usize = 0;
 
@@ -2831,26 +2830,26 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
         const slice = self.sections.slice();
         var sect_id: usize = 0;
         for (self.segments.items) |seg| {
-            try writer.writeStruct(seg);
+            try writer.writeStruct(seg, .little);
             for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
-                try writer.writeStruct(header);
+                try writer.writeStruct(header, .little);
             }
             sect_id += seg.nsects;
         }
         ncmds += self.segments.items.len;
     }
 
-    try writer.writeStruct(self.dyld_info_cmd);
+    try writer.writeStruct(self.dyld_info_cmd, .little);
     ncmds += 1;
-    try writer.writeStruct(self.function_starts_cmd);
+    try writer.writeStruct(self.function_starts_cmd, .little);
     ncmds += 1;
-    try writer.writeStruct(self.data_in_code_cmd);
+    try writer.writeStruct(self.data_in_code_cmd, .little);
     ncmds += 1;
-    try writer.writeStruct(self.symtab_cmd);
+    try writer.writeStruct(self.symtab_cmd, .little);
     ncmds += 1;
-    try writer.writeStruct(self.dysymtab_cmd);
+    try writer.writeStruct(self.dysymtab_cmd, .little);
     ncmds += 1;
-    try load_commands.writeDylinkerLC(writer);
+    try load_commands.writeDylinkerLC(&writer);
     ncmds += 1;
 
     if (self.getInternalObject()) |obj| {
@@ -2861,44 +2860,44 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
                 0
             else
                 @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));
-            try writer.writeStruct(macho.entry_point_command{
+            try writer.writeStruct(@as(macho.entry_point_command, .{
                 .entryoff = entryoff,
                 .stacksize = self.base.stack_size,
-            });
+            }), .little);
             ncmds += 1;
         }
     }
 
     if (self.base.isDynLib()) {
-        try load_commands.writeDylibIdLC(self, writer);
+        try load_commands.writeDylibIdLC(self, &writer);
         ncmds += 1;
     }
 
     for (self.rpath_list) |rpath| {
-        try load_commands.writeRpathLC(rpath, writer);
+        try load_commands.writeRpathLC(rpath, &writer);
         ncmds += 1;
     }
     if (comp.config.any_sanitize_thread) {
         const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
         defer gpa.free(path);
         const rpath = std.fs.path.dirname(path) orelse ".";
-        try load_commands.writeRpathLC(rpath, writer);
+        try load_commands.writeRpathLC(rpath, &writer);
         ncmds += 1;
     }
 
-    try writer.writeStruct(macho.source_version_command{ .version = 0 });
+    try writer.writeStruct(@as(macho.source_version_command, .{ .version = 0 }), .little);
     ncmds += 1;
 
     if (self.platform.isBuildVersionCompatible()) {
-        try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, writer);
+        try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, &writer);
         ncmds += 1;
     } else {
-        try load_commands.writeVersionMinLC(self.platform, self.sdk_version, writer);
+        try load_commands.writeVersionMinLC(self.platform, self.sdk_version, &writer);
         ncmds += 1;
     }
 
-    const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos;
-    try writer.writeStruct(self.uuid_cmd);
+    const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + writer.end;
+    try writer.writeStruct(self.uuid_cmd, .little);
     ncmds += 1;
 
     for (self.dylibs.items) |index| {
@@ -2916,16 +2915,16 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
             .timestamp = dylib_id.timestamp,
             .current_version = dylib_id.current_version,
             .compatibility_version = dylib_id.compatibility_version,
-        }, writer);
+        }, &writer);
         ncmds += 1;
     }
 
     if (self.requiresCodeSig()) {
-        try writer.writeStruct(self.codesig_cmd);
+        try writer.writeStruct(self.codesig_cmd, .little);
         ncmds += 1;
     }
 
-    assert(stream.pos == needed_size);
+    assert(writer.end == needed_size);
 
     try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
 
@@ -3014,25 +3013,26 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
 pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
     const seg = self.getTextSegment();
     const offset = self.codesig_cmd.dataoff;
+    const gpa = self.base.comp.gpa;
 
-    var buffer = std.array_list.Managed(u8).init(self.base.comp.gpa);
-    defer buffer.deinit();
-    try buffer.ensureTotalCapacityPrecise(code_sig.size());
+    const buffer = try gpa.alloc(u8, code_sig.size());
+    defer gpa.free(buffer);
+    var writer: Writer = .fixed(buffer);
     try code_sig.writeAdhocSignature(self, .{
         .file = self.base.file.?,
         .exec_seg_base = seg.fileoff,
         .exec_seg_limit = seg.filesize,
         .file_size = offset,
         .dylib = self.base.isDynLib(),
-    }, buffer.writer());
-    assert(buffer.items.len == code_sig.size());
+    }, &writer);
+    assert(writer.buffered().len == code_sig.size());
 
     log.debug("writing code signature from 0x{x} to 0x{x}", .{
         offset,
-        offset + buffer.items.len,
+        offset + writer.buffered().len,
     });
 
-    try self.pwriteAll(buffer.items, offset);
+    try self.pwriteAll(writer.buffered(), offset);
 }
 
 pub fn updateFunc(
@@ -5372,7 +5372,7 @@ const macho = std.macho;
 const math = std.math;
 const mem = std.mem;
 const meta = std.meta;
-const Writer = std.io.Writer;
+const Writer = std.Io.Writer;
 
 const aarch64 = codegen.aarch64.encoding;
 const bind = @import("MachO/dyld_info/bind.zig");