Commit 49be02e6d7

Andrew Kelley <andrew@ziglang.org>
2025-07-02 03:40:50
MachO: revert unfinished changes
1 parent c8fcd2f
src/link/MachO/dyld_info/bind.zig
@@ -1,7 +1,7 @@
 pub const Entry = struct {
     target: MachO.Ref,
     offset: u64,
-    segment_id: u4,
+    segment_id: u8,
     addend: i64,
 
     pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool {
@@ -20,12 +20,14 @@ pub const Bind = struct {
     entries: std.ArrayListUnmanaged(Entry) = .empty,
     buffer: std.ArrayListUnmanaged(u8) = .empty,
 
-    pub fn deinit(bind: *Bind, gpa: Allocator) void {
-        bind.entries.deinit(gpa);
-        bind.buffer.deinit(gpa);
+    const Self = @This();
+
+    pub fn deinit(self: *Self, gpa: Allocator) void {
+        self.entries.deinit(gpa);
+        self.buffer.deinit(gpa);
     }
 
-    pub fn updateSize(bind: *Bind, macho_file: *MachO) !void {
+    pub fn updateSize(self: *Self, macho_file: *MachO) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
@@ -54,12 +56,15 @@ pub const Bind = struct {
                     const addend = rel.addend + rel.getRelocAddend(cpu_arch);
                     const sym = rel.getTargetSymbol(atom.*, macho_file);
                     if (sym.isTlvInit(macho_file)) continue;
-                    if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) (try bind.entries.addOne(gpa)).* = .{
+                    const entry = Entry{
                         .target = rel.getTargetSymbolRef(atom.*, macho_file),
                         .offset = atom_addr + rel_offset - seg.vmaddr,
                         .segment_id = seg_id,
                         .addend = addend,
                     };
+                    if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) {
+                        try self.entries.append(gpa, entry);
+                    }
                 }
             }
         }
@@ -70,12 +75,15 @@ pub const Bind = struct {
             for (macho_file.got.symbols.items, 0..) |ref, idx| {
                 const sym = ref.getSymbol(macho_file).?;
                 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
-                if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{
+                const entry = Entry{
                     .target = ref,
                     .offset = addr - seg.vmaddr,
                     .segment_id = seg_id,
                     .addend = 0,
                 };
+                if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) {
+                    try self.entries.append(gpa, entry);
+                }
             }
         }
 
@@ -86,12 +94,15 @@ pub const Bind = struct {
             for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
                 const sym = ref.getSymbol(macho_file).?;
                 const addr = sect.addr + idx * @sizeOf(u64);
-                if (sym.flags.import and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
+                const bind_entry = Entry{
                     .target = ref,
                     .offset = addr - seg.vmaddr,
                     .segment_id = seg_id,
                     .addend = 0,
                 };
+                if (sym.flags.import and sym.flags.weak) {
+                    try self.entries.append(gpa, bind_entry);
+                }
             }
         }
 
@@ -102,48 +113,49 @@ pub const Bind = struct {
             for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
                 const sym = ref.getSymbol(macho_file).?;
                 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);
-                if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{
+                const entry = Entry{
                     .target = ref,
                     .offset = addr - seg.vmaddr,
                     .segment_id = seg_id,
                     .addend = 0,
                 };
+                if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) {
+                    try self.entries.append(gpa, entry);
+                }
             }
         }
 
-        try bind.finalize(gpa, macho_file);
-        macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
+        try self.finalize(gpa, macho_file);
+        macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
     }
 
-    fn finalize(bind: *Bind, gpa: Allocator, ctx: *MachO) !void {
-        if (bind.entries.items.len == 0) return;
+    fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
+        if (self.entries.items.len == 0) return;
 
-        var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
-        const bw = &aw.writer;
-        defer bind.buffer = aw.toArrayList();
+        const writer = self.buffer.writer(gpa);
 
         log.debug("bind opcodes", .{});
 
-        std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan);
+        std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
 
         var start: usize = 0;
         var seg_id: ?u8 = null;
-        for (bind.entries.items, 0..) |entry, i| {
+        for (self.entries.items, 0..) |entry, i| {
             if (seg_id != null and seg_id.? == entry.segment_id) continue;
-            try finalizeSegment(bind.entries.items[start..i], ctx, bw);
+            try finalizeSegment(self.entries.items[start..i], ctx, writer);
             seg_id = entry.segment_id;
             start = i;
         }
 
-        try finalizeSegment(bind.entries.items[start..], ctx, bw);
-        try done(bw);
+        try finalizeSegment(self.entries.items[start..], ctx, writer);
+        try done(writer);
     }
 
-    fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void {
+    fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {
         if (entries.len == 0) return;
 
         const seg_id = entries[0].segment_id;
-        try setSegmentOffset(seg_id, 0, bw);
+        try setSegmentOffset(seg_id, 0, writer);
 
         var offset: u64 = 0;
         var addend: i64 = 0;
@@ -163,15 +175,15 @@ pub const Bind = struct {
             if (target == null or !target.?.eql(current.target)) {
                 switch (state) {
                     .start => {},
-                    .bind_single => try doBind(bw),
-                    .bind_times_skip => try doBindTimesSkip(count, skip, bw),
+                    .bind_single => try doBind(writer),
+                    .bind_times_skip => try doBindTimesSkip(count, skip, writer),
                 }
                 state = .start;
                 target = current.target;
 
                 const sym = current.target.getSymbol(ctx).?;
                 const name = sym.getName(ctx);
-                const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
+                const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
                 const ordinal: i16 = ord: {
                     if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
                     if (sym.flags.import) {
@@ -183,13 +195,13 @@ pub const Bind = struct {
                     break :ord macho.BIND_SPECIAL_DYLIB_SELF;
                 };
 
-                try setSymbol(name, flags, bw);
-                try setTypePointer(bw);
-                try setDylibOrdinal(ordinal, bw);
+                try setSymbol(name, flags, writer);
+                try setTypePointer(writer);
+                try setDylibOrdinal(ordinal, writer);
 
                 if (current.addend != addend) {
                     addend = current.addend;
-                    try setAddend(addend, bw);
+                    try setAddend(addend, writer);
                 }
             }
 
@@ -198,11 +210,11 @@ pub const Bind = struct {
             switch (state) {
                 .start => {
                     if (current.offset < offset) {
-                        try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), bw);
+                        try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), writer);
                         offset = offset - (offset - current.offset);
                     } else if (current.offset > offset) {
                         const delta = current.offset - offset;
-                        try addAddr(delta, bw);
+                        try addAddr(delta, writer);
                         offset += delta;
                     }
                     state = .bind_single;
@@ -211,7 +223,7 @@ pub const Bind = struct {
                 },
                 .bind_single => {
                     if (current.offset == offset) {
-                        try doBind(bw);
+                        try doBind(writer);
                         state = .start;
                     } else if (current.offset > offset) {
                         const delta = current.offset - offset;
@@ -225,9 +237,9 @@ pub const Bind = struct {
                     if (current.offset < offset) {
                         count -= 1;
                         if (count == 1) {
-                            try doBindAddAddr(skip, bw);
+                            try doBindAddAddr(skip, writer);
                         } else {
-                            try doBindTimesSkip(count, skip, bw);
+                            try doBindTimesSkip(count, skip, writer);
                         }
                         state = .start;
                         offset = offset - (@sizeOf(u64) + skip);
@@ -236,7 +248,7 @@ pub const Bind = struct {
                         count += 1;
                         offset += @sizeOf(u64) + skip;
                     } else {
-                        try doBindTimesSkip(count, skip, bw);
+                        try doBindTimesSkip(count, skip, writer);
                         state = .start;
                         i -= 1;
                     }
@@ -246,13 +258,13 @@ pub const Bind = struct {
 
         switch (state) {
             .start => unreachable,
-            .bind_single => try doBind(bw),
-            .bind_times_skip => try doBindTimesSkip(count, skip, bw),
+            .bind_single => try doBind(writer),
+            .bind_times_skip => try doBindTimesSkip(count, skip, writer),
         }
     }
 
-    pub fn write(bind: Bind, bw: *Writer) Writer.Error!void {
-        try bw.writeAll(bind.buffer.items);
+    pub fn write(self: Self, writer: anytype) !void {
+        try writer.writeAll(self.buffer.items);
     }
 };
 
@@ -260,12 +272,14 @@ pub const WeakBind = struct {
     entries: std.ArrayListUnmanaged(Entry) = .empty,
     buffer: std.ArrayListUnmanaged(u8) = .empty,
 
-    pub fn deinit(bind: *WeakBind, gpa: Allocator) void {
-        bind.entries.deinit(gpa);
-        bind.buffer.deinit(gpa);
+    const Self = @This();
+
+    pub fn deinit(self: *Self, gpa: Allocator) void {
+        self.entries.deinit(gpa);
+        self.buffer.deinit(gpa);
     }
 
-    pub fn updateSize(bind: *WeakBind, macho_file: *MachO) !void {
+    pub fn updateSize(self: *Self, macho_file: *MachO) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
@@ -294,12 +308,15 @@ pub const WeakBind = struct {
                     const addend = rel.addend + rel.getRelocAddend(cpu_arch);
                     const sym = rel.getTargetSymbol(atom.*, macho_file);
                     if (sym.isTlvInit(macho_file)) continue;
-                    if (!sym.isLocal() and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
+                    const entry = Entry{
                         .target = rel.getTargetSymbolRef(atom.*, macho_file),
                         .offset = atom_addr + rel_offset - seg.vmaddr,
                         .segment_id = seg_id,
                         .addend = addend,
                     };
+                    if (!sym.isLocal() and sym.flags.weak) {
+                        try self.entries.append(gpa, entry);
+                    }
                 }
             }
         }
@@ -310,12 +327,15 @@ pub const WeakBind = struct {
             for (macho_file.got.symbols.items, 0..) |ref, idx| {
                 const sym = ref.getSymbol(macho_file).?;
                 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
-                if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
+                const entry = Entry{
                     .target = ref,
                     .offset = addr - seg.vmaddr,
                     .segment_id = seg_id,
                     .addend = 0,
                 };
+                if (sym.flags.weak) {
+                    try self.entries.append(gpa, entry);
+                }
             }
         }
 
@@ -327,12 +347,15 @@ pub const WeakBind = struct {
             for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
                 const sym = ref.getSymbol(macho_file).?;
                 const addr = sect.addr + idx * @sizeOf(u64);
-                if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
+                const bind_entry = Entry{
                     .target = ref,
                     .offset = addr - seg.vmaddr,
                     .segment_id = seg_id,
                     .addend = 0,
                 };
+                if (sym.flags.weak) {
+                    try self.entries.append(gpa, bind_entry);
+                }
             }
         }
 
@@ -343,48 +366,49 @@ pub const WeakBind = struct {
             for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
                 const sym = ref.getSymbol(macho_file).?;
                 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);
-                if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
+                const entry = Entry{
                     .target = ref,
                     .offset = addr - seg.vmaddr,
                     .segment_id = seg_id,
                     .addend = 0,
                 };
+                if (sym.flags.weak) {
+                    try self.entries.append(gpa, entry);
+                }
             }
         }
 
-        try bind.finalize(gpa, macho_file);
-        macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
+        try self.finalize(gpa, macho_file);
+        macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
     }
 
-    fn finalize(bind: *WeakBind, gpa: Allocator, ctx: *MachO) !void {
-        if (bind.entries.items.len == 0) return;
+    fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
+        if (self.entries.items.len == 0) return;
 
-        var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
-        const bw = &aw.writer;
-        defer bind.buffer = aw.toArrayList();
+        const writer = self.buffer.writer(gpa);
 
         log.debug("weak bind opcodes", .{});
 
-        std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan);
+        std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
 
         var start: usize = 0;
         var seg_id: ?u8 = null;
-        for (bind.entries.items, 0..) |entry, i| {
+        for (self.entries.items, 0..) |entry, i| {
             if (seg_id != null and seg_id.? == entry.segment_id) continue;
-            try finalizeSegment(bind.entries.items[start..i], ctx, bw);
+            try finalizeSegment(self.entries.items[start..i], ctx, writer);
             seg_id = entry.segment_id;
             start = i;
         }
 
-        try finalizeSegment(bind.entries.items[start..], ctx, bw);
-        try done(bw);
+        try finalizeSegment(self.entries.items[start..], ctx, writer);
+        try done(writer);
     }
 
-    fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void {
+    fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {
         if (entries.len == 0) return;
 
         const seg_id = entries[0].segment_id;
-        try setSegmentOffset(seg_id, 0, bw);
+        try setSegmentOffset(seg_id, 0, writer);
 
         var offset: u64 = 0;
         var addend: i64 = 0;
@@ -404,8 +428,8 @@ pub const WeakBind = struct {
             if (target == null or !target.?.eql(current.target)) {
                 switch (state) {
                     .start => {},
-                    .bind_single => try doBind(bw),
-                    .bind_times_skip => try doBindTimesSkip(count, skip, bw),
+                    .bind_single => try doBind(writer),
+                    .bind_times_skip => try doBindTimesSkip(count, skip, writer),
                 }
                 state = .start;
                 target = current.target;
@@ -414,12 +438,12 @@ pub const WeakBind = struct {
                 const name = sym.getName(ctx);
                 const flags: u8 = 0; // TODO NON_WEAK_DEFINITION
 
-                try setSymbol(name, flags, bw);
-                try setTypePointer(bw);
+                try setSymbol(name, flags, writer);
+                try setTypePointer(writer);
 
                 if (current.addend != addend) {
                     addend = current.addend;
-                    try setAddend(addend, bw);
+                    try setAddend(addend, writer);
                 }
             }
 
@@ -428,11 +452,11 @@ pub const WeakBind = struct {
             switch (state) {
                 .start => {
                     if (current.offset < offset) {
-                        try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), bw);
+                        try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), writer);
                         offset = offset - (offset - current.offset);
                     } else if (current.offset > offset) {
                         const delta = current.offset - offset;
-                        try addAddr(delta, bw);
+                        try addAddr(delta, writer);
                         offset += delta;
                     }
                     state = .bind_single;
@@ -441,7 +465,7 @@ pub const WeakBind = struct {
                 },
                 .bind_single => {
                     if (current.offset == offset) {
-                        try doBind(bw);
+                        try doBind(writer);
                         state = .start;
                     } else if (current.offset > offset) {
                         const delta = current.offset - offset;
@@ -455,9 +479,9 @@ pub const WeakBind = struct {
                     if (current.offset < offset) {
                         count -= 1;
                         if (count == 1) {
-                            try doBindAddAddr(skip, bw);
+                            try doBindAddAddr(skip, writer);
                         } else {
-                            try doBindTimesSkip(count, skip, bw);
+                            try doBindTimesSkip(count, skip, writer);
                         }
                         state = .start;
                         offset = offset - (@sizeOf(u64) + skip);
@@ -466,7 +490,7 @@ pub const WeakBind = struct {
                         count += 1;
                         offset += @sizeOf(u64) + skip;
                     } else {
-                        try doBindTimesSkip(count, skip, bw);
+                        try doBindTimesSkip(count, skip, writer);
                         state = .start;
                         i -= 1;
                     }
@@ -476,13 +500,13 @@ pub const WeakBind = struct {
 
         switch (state) {
             .start => unreachable,
-            .bind_single => try doBind(bw),
-            .bind_times_skip => try doBindTimesSkip(count, skip, bw),
+            .bind_single => try doBind(writer),
+            .bind_times_skip => try doBindTimesSkip(count, skip, writer),
         }
     }
 
-    pub fn write(bind: WeakBind, bw: *Writer) Writer.Error!void {
-        try bw.writeAll(bind.buffer.items);
+    pub fn write(self: Self, writer: anytype) !void {
+        try writer.writeAll(self.buffer.items);
     }
 };
 
@@ -491,13 +515,15 @@ pub const LazyBind = struct {
     buffer: std.ArrayListUnmanaged(u8) = .empty,
     offsets: std.ArrayListUnmanaged(u32) = .empty,
 
-    pub fn deinit(bind: *LazyBind, gpa: Allocator) void {
-        bind.entries.deinit(gpa);
-        bind.buffer.deinit(gpa);
-        bind.offsets.deinit(gpa);
+    const Self = @This();
+
+    pub fn deinit(self: *Self, gpa: Allocator) void {
+        self.entries.deinit(gpa);
+        self.buffer.deinit(gpa);
+        self.offsets.deinit(gpa);
     }
 
-    pub fn updateSize(bind: *LazyBind, macho_file: *MachO) !void {
+    pub fn updateSize(self: *Self, macho_file: *MachO) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
@@ -511,35 +537,36 @@ pub const LazyBind = struct {
         for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
             const sym = ref.getSymbol(macho_file).?;
             const addr = sect.addr + idx * @sizeOf(u64);
-            if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{
+            const bind_entry = Entry{
                 .target = ref,
                 .offset = addr - seg.vmaddr,
                 .segment_id = seg_id,
                 .addend = 0,
             };
+            if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) {
+                try self.entries.append(gpa, bind_entry);
+            }
         }
 
-        try bind.finalize(gpa, macho_file);
-        macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
+        try self.finalize(gpa, macho_file);
+        macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
     }
 
-    fn finalize(bind: *LazyBind, gpa: Allocator, ctx: *MachO) !void {
-        try bind.offsets.ensureTotalCapacityPrecise(gpa, bind.entries.items.len);
+    fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
+        try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);
 
-        var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
-        const bw = &aw.writer;
-        defer bind.buffer = aw.toArrayList();
+        const writer = self.buffer.writer(gpa);
 
         log.debug("lazy bind opcodes", .{});
 
         var addend: i64 = 0;
 
-        for (bind.entries.items) |entry| {
-            bind.offsets.appendAssumeCapacity(@intCast(bind.buffer.items.len));
+        for (self.entries.items) |entry| {
+            self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len));
 
             const sym = entry.target.getSymbol(ctx).?;
             const name = sym.getName(ctx);
-            const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
+            const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
             const ordinal: i16 = ord: {
                 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
                 if (sym.flags.import) {
@@ -551,116 +578,121 @@ pub const LazyBind = struct {
                 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
             };
 
-            try setSegmentOffset(entry.segment_id, entry.offset, bw);
-            try setSymbol(name, flags, bw);
-            try setDylibOrdinal(ordinal, bw);
+            try setSegmentOffset(entry.segment_id, entry.offset, writer);
+            try setSymbol(name, flags, writer);
+            try setDylibOrdinal(ordinal, writer);
 
             if (entry.addend != addend) {
-                try setAddend(entry.addend, bw);
+                try setAddend(entry.addend, writer);
                 addend = entry.addend;
             }
 
-            try doBind(bw);
-            try done(bw);
+            try doBind(writer);
+            try done(writer);
         }
     }
 
-    pub fn write(bind: LazyBind, bw: *Writer) Writer.Error!void {
-        try bw.writeAll(bind.buffer.items);
+    pub fn write(self: Self, writer: anytype) !void {
+        try writer.writeAll(self.buffer.items);
     }
 };
 
-fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {
+fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
     log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
-    try bw.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segment_id);
-    try bw.writeLeb128(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: u4, bw: *Writer) Writer.Error!void {
+fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void {
     log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });
-    try bw.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags);
-    try bw.writeAll(name);
-    try bw.writeByte(0);
+    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(bw: *Writer) Writer.Error!void {
+fn setTypePointer(writer: anytype) !void {
     log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});
-    try bw.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.BIND_TYPE_POINTER)));
+    try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER)));
 }
 
-fn setDylibOrdinal(ordinal: i16, bw: *Writer) Writer.Error!void {
-    switch (ordinal) {
-        else => unreachable, // Invalid dylib special binding
-        macho.BIND_SPECIAL_DYLIB_SELF,
-        macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE,
-        macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP,
-        => {
-            log.debug(">>> set dylib special: {d}", .{ordinal});
-            try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @bitCast(@as(i4, @intCast(ordinal)))));
-        },
-        1...std.math.maxInt(i16) => {
-            log.debug(">>> set dylib ordinal: {d}", .{ordinal});
-            if (std.math.cast(u4, ordinal)) |imm| {
-                try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | imm);
-            } else {
-                try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
-                try bw.writeUleb128(ordinal);
-            }
-        },
+fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {
+    if (ordinal <= 0) {
+        switch (ordinal) {
+            macho.BIND_SPECIAL_DYLIB_SELF,
+            macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE,
+            macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP,
+            => {},
+            else => unreachable, // Invalid dylib special binding
+        }
+        log.debug(">>> set dylib special: {d}", .{ordinal});
+        const cast = @as(u16, @bitCast(ordinal));
+        try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @truncate(cast)));
+    } else {
+        const cast = @as(u16, @bitCast(ordinal));
+        log.debug(">>> set dylib ordinal: {d}", .{ordinal});
+        if (cast <= 0xf) {
+            try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @as(u4, @truncate(cast)));
+        } else {
+            try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+            try std.leb.writeUleb128(writer, cast);
+        }
     }
 }
 
-fn setAddend(addend: i64, bw: *Writer) Writer.Error!void {
+fn setAddend(addend: i64, writer: anytype) !void {
     log.debug(">>> set addend: {x}", .{addend});
-    try bw.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
-    try bw.writeLeb128(addend);
+    try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
+    try std.leb.writeIleb128(writer, addend);
 }
 
-fn doBind(bw: *Writer) Writer.Error!void {
+fn doBind(writer: anytype) !void {
     log.debug(">>> bind", .{});
-    try bw.writeByte(macho.BIND_OPCODE_DO_BIND);
+    try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
 }
 
-fn doBindAddAddr(addr: u64, bw: *Writer) Writer.Error!void {
+fn doBindAddAddr(addr: u64, writer: anytype) !void {
     log.debug(">>> bind with add: {x}", .{addr});
-    if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| {
-        if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte(
-            macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | imm_scaled,
-        );
-    } else |_| {}
-    try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
-    try bw.writeLeb128(addr);
+    if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {
+        const imm = @divExact(addr, @sizeOf(u64));
+        if (imm <= 0xf) {
+            try writer.writeByte(
+                macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)),
+            );
+            return;
+        }
+    }
+    try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
+    try std.leb.writeUleb128(writer, addr);
 }
 
-fn doBindTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {
+fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void {
     log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });
-    try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
-    try bw.writeLeb128(count);
-    try bw.writeLeb128(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, bw: *Writer) Writer.Error!void {
+fn addAddr(addr: u64, writer: anytype) !void {
     log.debug(">>> add: {x}", .{addr});
-    try bw.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
-    try bw.writeLeb128(addr);
+    try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
+    try std.leb.writeUleb128(writer, addr);
 }
 
-fn done(bw: *Writer) Writer.Error!void {
+fn done(writer: anytype) !void {
     log.debug(">>> done", .{});
-    try bw.writeByte(macho.BIND_OPCODE_DONE);
+    try writer.writeByte(macho.BIND_OPCODE_DONE);
 }
 
-const std = @import("std");
 const assert = std.debug.assert;
 const leb = std.leb;
 const log = std.log.scoped(.link_dyld_info);
 const macho = std.macho;
 const mem = std.mem;
 const testing = std.testing;
-const Allocator = std.mem.Allocator;
-const Writer = std.io.Writer;
-
 const trace = @import("../../../tracy.zig").trace;
+const std = @import("std");
+
+const Allocator = mem.Allocator;
 const File = @import("../file.zig").File;
 const MachO = @import("../../MachO.zig");
 const Symbol = @import("../Symbol.zig");
src/link/MachO/dyld_info/Rebase.zig
@@ -3,7 +3,7 @@ buffer: std.ArrayListUnmanaged(u8) = .empty,
 
 pub const Entry = struct {
     offset: u64,
-    segment_id: u4,
+    segment_id: u8,
 
     pub fn lessThan(ctx: void, entry: Entry, other: Entry) bool {
         _ = ctx;
@@ -110,35 +110,33 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
 fn finalize(rebase: *Rebase, gpa: Allocator) !void {
     if (rebase.entries.items.len == 0) return;
 
-    var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &rebase.buffer);
-    const bw = &aw.writer;
-    defer rebase.buffer = aw.toArrayList();
+    const writer = rebase.buffer.writer(gpa);
 
     log.debug("rebase opcodes", .{});
 
     std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);
 
-    try setTypePointer(bw);
+    try setTypePointer(writer);
 
     var start: usize = 0;
     var seg_id: ?u8 = null;
     for (rebase.entries.items, 0..) |entry, i| {
         if (seg_id != null and seg_id.? == entry.segment_id) continue;
-        try finalizeSegment(rebase.entries.items[start..i], bw);
+        try finalizeSegment(rebase.entries.items[start..i], writer);
         seg_id = entry.segment_id;
         start = i;
     }
 
-    try finalizeSegment(rebase.entries.items[start..], bw);
-    try done(bw);
+    try finalizeSegment(rebase.entries.items[start..], writer);
+    try done(writer);
 }
 
-fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
+fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
     if (entries.len == 0) return;
 
     const segment_id = entries[0].segment_id;
     var offset = entries[0].offset;
-    try setSegmentOffset(segment_id, offset, bw);
+    try setSegmentOffset(segment_id, offset, writer);
 
     var count: usize = 0;
     var skip: u64 = 0;
@@ -157,7 +155,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
             .start => {
                 if (offset < current_offset) {
                     const delta = current_offset - offset;
-                    try addAddr(delta, bw);
+                    try addAddr(delta, writer);
                     offset += delta;
                 }
                 state = .times;
@@ -177,7 +175,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
                     offset += skip;
                     i -= 1;
                 } else {
-                    try rebaseTimes(count, bw);
+                    try rebaseTimes(count, writer);
                     state = .start;
                     i -= 1;
                 }
@@ -186,9 +184,9 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
                 if (current_offset < offset) {
                     count -= 1;
                     if (count == 1) {
-                        try rebaseAddAddr(skip, bw);
+                        try rebaseAddAddr(skip, writer);
                     } else {
-                        try rebaseTimesSkip(count, skip, bw);
+                        try rebaseTimesSkip(count, skip, writer);
                     }
                     state = .start;
                     offset = offset - (@sizeOf(u64) + skip);
@@ -201,7 +199,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
                     count += 1;
                     offset += @sizeOf(u64) + skip;
                 } else {
-                    try rebaseTimesSkip(count, skip, bw);
+                    try rebaseTimesSkip(count, skip, writer);
                     state = .start;
                     i -= 1;
                 }
@@ -212,66 +210,68 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
     switch (state) {
         .start => unreachable,
         .times => {
-            try rebaseTimes(count, bw);
+            try rebaseTimes(count, writer);
         },
         .times_skip => {
-            try rebaseTimesSkip(count, skip, bw);
+            try rebaseTimesSkip(count, skip, writer);
         },
     }
 }
 
-fn setTypePointer(bw: *Writer) Writer.Error!void {
+fn setTypePointer(writer: anytype) !void {
     log.debug(">>> set type: {d}", .{macho.REBASE_TYPE_POINTER});
-    try bw.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.REBASE_TYPE_POINTER)));
+    try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.REBASE_TYPE_POINTER)));
 }
 
-fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {
+fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
     log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
-    try bw.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
-    try bw.writeLeb128(offset);
+    try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
+    try std.leb.writeUleb128(writer, offset);
 }
 
-fn rebaseAddAddr(addr: u64, bw: *Writer) Writer.Error!void {
+fn rebaseAddAddr(addr: u64, writer: anytype) !void {
     log.debug(">>> rebase with add: {x}", .{addr});
-    try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
-    try bw.writeLeb128(addr);
+    try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
+    try std.leb.writeUleb128(writer, addr);
 }
 
-fn rebaseTimes(count: usize, bw: *Writer) Writer.Error!void {
+fn rebaseTimes(count: usize, writer: anytype) !void {
     log.debug(">>> rebase with count: {d}", .{count});
     if (count <= 0xf) {
-        try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count)));
+        try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count)));
     } else {
-        try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
-        try bw.writeLeb128(count);
+        try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
+        try std.leb.writeUleb128(writer, count);
     }
 }
 
-fn rebaseTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {
+fn rebaseTimesSkip(count: usize, skip: u64, writer: anytype) !void {
     log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip });
-    try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
-    try bw.writeLeb128(count);
-    try bw.writeLeb128(skip);
+    try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
+    try std.leb.writeUleb128(writer, count);
+    try std.leb.writeUleb128(writer, skip);
 }
 
-fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {
+fn addAddr(addr: u64, writer: anytype) !void {
     log.debug(">>> add: {x}", .{addr});
-    if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| {
-        if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte(
-            macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | imm_scaled,
-        );
-    } else |_| {}
-    try bw.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);
-    try bw.writeLeb128(addr);
+    if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {
+        const imm = @divExact(addr, @sizeOf(u64));
+        if (imm <= 0xf) {
+            try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)));
+            return;
+        }
+    }
+    try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);
+    try std.leb.writeUleb128(writer, addr);
 }
 
-fn done(bw: *Writer) Writer.Error!void {
+fn done(writer: anytype) !void {
     log.debug(">>> done", .{});
-    try bw.writeByte(macho.REBASE_OPCODE_DONE);
+    try writer.writeByte(macho.REBASE_OPCODE_DONE);
 }
 
-pub fn write(rebase: Rebase, bw: *Writer) Writer.Error!void {
-    try bw.writeAll(rebase.buffer.items);
+pub fn write(rebase: Rebase, writer: anytype) !void {
+    try writer.writeAll(rebase.buffer.items);
 }
 
 test "rebase - no entries" {
src/link/MachO/dyld_info/Trie.zig
@@ -31,7 +31,7 @@
 
 /// The root node of the trie.
 root: ?Node.Index = null,
-buffer: []u8 = &.{},
+buffer: std.ArrayListUnmanaged(u8) = .empty,
 nodes: std.MultiArrayList(Node) = .{},
 edges: std.ArrayListUnmanaged(Edge) = .empty,
 
@@ -123,7 +123,7 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void {
 
     try self.finalize(gpa);
 
-    macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.len), @alignOf(u64));
+    macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
 }
 
 /// Finalizes this trie for writing to a byte stream.
@@ -138,7 +138,7 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
     defer ordered_nodes.deinit();
     try ordered_nodes.ensureTotalCapacityPrecise(self.nodes.items(.is_terminal).len);
 
-    var fifo = DeprecatedLinearFifo(Node.Index).init(allocator);
+    var fifo = std.fifo.LinearFifo(Node.Index, .Dynamic).init(allocator);
     defer fifo.deinit();
 
     try fifo.writeItem(self.root.?);
@@ -164,11 +164,9 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
         }
     }
 
-    assert(self.buffer.len == 0);
-    self.buffer = try allocator.alloc(u8, size);
-    var bw: Writer = .fixed(self.buffer);
+    try self.buffer.ensureTotalCapacityPrecise(allocator, size);
     for (ordered_nodes.items) |node_index| {
-        try self.writeNode(node_index, &bw);
+        try self.writeNode(node_index, self.buffer.writer(allocator));
     }
 }
 
@@ -183,17 +181,17 @@ const FinalizeNodeResult = struct {
 
 /// Updates offset of this node in the output byte stream.
 fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult {
-    var buf: [1024]u8 = undefined;
-    var bw: Writer = .discarding(&buf);
+    var stream = std.io.countingWriter(std.io.null_writer);
+    const writer = stream.writer();
     const slice = self.nodes.slice();
 
     var node_size: u32 = 0;
     if (slice.items(.is_terminal)[node_index]) {
         const export_flags = slice.items(.export_flags)[node_index];
         const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
-        try bw.writeLeb128(export_flags);
-        try bw.writeLeb128(vmaddr_offset);
-        try bw.writeLeb128(bw.count);
+        try leb.writeULEB128(writer, export_flags);
+        try leb.writeULEB128(writer, vmaddr_offset);
+        try leb.writeULEB128(writer, stream.bytes_written);
     } else {
         node_size += 1; // 0x0 for non-terminal nodes
     }
@@ -203,13 +201,13 @@ fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !Final
         const edge = &self.edges.items[edge_index];
         const next_node_offset = slice.items(.trie_offset)[edge.node];
         node_size += @intCast(edge.label.len + 1);
-        try bw.writeLeb128(next_node_offset);
+        try leb.writeULEB128(writer, next_node_offset);
     }
 
     const trie_offset = slice.items(.trie_offset)[node_index];
     const updated = offset_in_trie != trie_offset;
     slice.items(.trie_offset)[node_index] = offset_in_trie;
-    node_size += @intCast(bw.count);
+    node_size += @intCast(stream.bytes_written);
 
     return .{ .node_size = node_size, .updated = updated };
 }
@@ -225,11 +223,12 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {
     }
     self.nodes.deinit(allocator);
     self.edges.deinit(allocator);
-    allocator.free(self.buffer);
+    self.buffer.deinit(allocator);
 }
 
-pub fn write(self: Trie, bw: *Writer) Writer.Error!void {
-    try bw.writeAll(self.buffer);
+pub fn write(self: Trie, writer: anytype) !void {
+    if (self.buffer.items.len == 0) return;
+    try writer.writeAll(self.buffer.items);
 }
 
 /// Writes this node to a byte stream.
@@ -238,7 +237,7 @@ pub fn write(self: Trie, bw: *Writer) Writer.Error!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, bw: *Writer) !void {
+fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
     const slice = self.nodes.slice();
     const edges = slice.items(.edges)[node_index];
     const is_terminal = slice.items(.is_terminal)[node_index];
@@ -246,28 +245,36 @@ fn writeNode(self: *Trie, node_index: Node.Index, bw: *Writer) !void {
     const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
 
     if (is_terminal) {
-        const start = bw.count;
+        // 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);
         // 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);
-        // Terminal node info: encode export flags and vmaddr offset of this symbol.
-        try bw.writeLeb128(export_flags);
-        try bw.writeLeb128(vmaddr_offset);
+        try leb.writeULEB128(info_stream.writer(), export_flags);
+        try leb.writeULEB128(info_stream.writer(), vmaddr_offset);
+
         // Encode the size of the terminal node info.
-        try bw.writeLeb128(bw.count - start);
+        var size_buf: [@sizeOf(u64)]u8 = undefined;
+        var size_stream = std.io.fixedBufferStream(&size_buf);
+        try leb.writeULEB128(size_stream.writer(), info_stream.pos);
+
+        // 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]);
     } else {
         // Non-terminal node is delimited by 0 byte.
-        try bw.writeByte(0);
+        try writer.writeByte(0);
     }
-    // Write number of edges (max legal number of edges is 255).
-    try bw.writeByte(@intCast(edges.items.len));
+    // Write number of edges (max legal number of edges is 256).
+    try writer.writeByte(@as(u8, @intCast(edges.items.len)));
 
     for (edges.items) |edge_index| {
         const edge = self.edges.items[edge_index];
         // Write edge label and offset to next node in trie.
-        try bw.writeAll(edge.label);
-        try bw.writeByte(0);
-        try bw.writeLeb128(slice.items(.trie_offset)[edge.node]);
+        try writer.writeAll(edge.label);
+        try writer.writeByte(0);
+        try leb.writeULEB128(writer, slice.items(.trie_offset)[edge.node]);
     }
 }
 
@@ -407,10 +414,8 @@ const macho = std.macho;
 const mem = std.mem;
 const std = @import("std");
 const testing = std.testing;
-const Writer = std.io.Writer;
-
 const trace = @import("../../../tracy.zig").trace;
-const DeprecatedLinearFifo = @import("../../../deprecated.zig").LinearFifo;
+
 const Allocator = mem.Allocator;
 const MachO = @import("../../MachO.zig");
 const Trie = @This();
src/link/MachO/Archive.zig
@@ -71,29 +71,53 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
             .mtime = hdr.date() catch 0,
         };
 
-        log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path });
+        log.debug("extracting object '{}' from archive '{}'", .{ object.path, path });
 
         try self.objects.append(gpa, object);
     }
 }
 
 pub fn writeHeader(
-    bw: *Writer,
     object_name: []const u8,
     object_size: usize,
     format: Format,
-) Writer.Error!void {
-    var hdr: ar_hdr = undefined;
-    @memset(mem.asBytes(&hdr), ' ');
-    inline for (@typeInfo(ar_hdr).@"struct".fields) |field| @field(hdr, field.name)[0] = '0';
+    writer: anytype,
+) !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);
+
     const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format));
-    _ = std.fmt.bufPrint(&hdr.ar_name, "#1/{d}", .{object_name_len}) catch unreachable;
     const total_object_size = object_size + object_name_len;
-    _ = std.fmt.bufPrint(&hdr.ar_size, "{d}", .{total_object_size}) catch unreachable;
-    try bw.writeStruct(hdr);
-    try bw.writeAll(object_name);
-    try bw.splatByteAll(0, object_name_len - object_name.len);
+
+    {
+        var stream = std.io.fixedBufferStream(&hdr.ar_name);
+        stream.writer().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;
+    }
+
+    try writer.writeAll(mem.asBytes(&hdr));
+    try writer.print("{s}\x00", .{object_name});
+
+    const padding = object_name_len - object_name.len - 1;
+    if (padding > 0) {
+        try writer.writeByteNTimes(0, padding);
+    }
 }
 
 // Archive files start with the ARMAG identifying string.  Then follows a
@@ -177,12 +201,12 @@ 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, bw: *Writer, format: Format, macho_file: *MachO) Writer.Error!void {
+    pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: anytype) !void {
         const ptr_width = ptrWidth(format);
         // Header
-        try writeHeader(bw, SYMDEF, ar.size(format), format);
+        try writeHeader(SYMDEF, ar.size(format), format, writer);
         // Symtab size
-        try writeInt(bw, format, ar.entries.items.len * 2 * ptr_width);
+        try writeInt(format, ar.entries.items.len * 2 * ptr_width, writer);
         // Symtab entries
         for (ar.entries.items) |entry| {
             const file_off = switch (macho_file.getFile(entry.file).?) {
@@ -191,16 +215,19 @@ pub const ArSymtab = struct {
                 else => unreachable,
             };
             // Name offset
-            try writeInt(bw, format, entry.off);
+            try writeInt(format, entry.off, writer);
             // File offset
-            try writeInt(bw, format, file_off);
+            try writeInt(format, file_off, writer);
         }
         // Strtab size
         const strtab_size = mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
-        try writeInt(bw, format, strtab_size);
+        const padding = strtab_size - ar.strtab.buffer.items.len;
+        try writeInt(format, strtab_size, writer);
         // Strtab
-        try bw.writeAll(ar.strtab.buffer.items);
-        try bw.splatByteAll(0, strtab_size - ar.strtab.buffer.items.len);
+        try writer.writeAll(ar.strtab.buffer.items);
+        if (padding > 0) {
+            try writer.writeByteNTimes(0, padding);
+        }
     }
 
     const PrintFormat = struct {
@@ -248,10 +275,10 @@ pub fn ptrWidth(format: Format) usize {
     };
 }
 
-pub fn writeInt(bw: *Writer, format: Format, value: u64) Writer.Error!void {
+pub fn writeInt(format: Format, value: u64, writer: anytype) !void {
     switch (format) {
-        .p32 => try bw.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
-        .p64 => try bw.writeInt(u64, value, .little),
+        .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
+        .p64 => try writer.writeInt(u64, value, .little),
     }
 }
 
src/link/MachO/Atom.zig
@@ -580,9 +580,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
 
     relocs_log.debug("{x}: {s}", .{ self.value, name });
 
-    var bw: Writer = .fixed(buffer);
-
     var has_error = false;
+    var stream = std.io.fixedBufferStream(buffer);
     var i: usize = 0;
     while (i < relocs.len) : (i += 1) {
         const rel = relocs[i];
@@ -593,28 +592,30 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
             if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;
         }
 
-        bw.end = std.math.cast(usize, rel_offset) orelse return error.Overflow;
-        self.resolveRelocInner(rel, subtractor, buffer, macho_file, &bw) catch |err| switch (err) {
-            error.RelaxFail => {
-                const target = switch (rel.tag) {
-                    .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),
-                    .local => rel.getTargetAtom(self, macho_file).getName(macho_file),
-                };
-                try macho_file.reportParseError2(
-                    file.getIndex(),
-                    "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {f}, target {s}",
-                    .{
-                        name,
-                        self.getAddress(macho_file),
-                        rel.offset,
-                        rel.fmtPretty(macho_file.getTarget().cpu.arch),
-                        target,
-                    },
-                );
-                has_error = true;
-            },
-            error.RelaxFailUnexpectedInstruction => has_error = true,
-            else => |e| return e,
+        try stream.seekTo(rel_offset);
+        self.resolveRelocInner(rel, subtractor, buffer, macho_file, stream.writer()) catch |err| {
+            switch (err) {
+                error.RelaxFail => {
+                    const target = switch (rel.tag) {
+                        .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),
+                        .local => rel.getTargetAtom(self, macho_file).getName(macho_file),
+                    };
+                    try macho_file.reportParseError2(
+                        file.getIndex(),
+                        "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {}, target {s}",
+                        .{
+                            name,
+                            self.getAddress(macho_file),
+                            rel.offset,
+                            rel.fmtPretty(macho_file.getTarget().cpu.arch),
+                            target,
+                        },
+                    );
+                    has_error = true;
+                },
+                error.RelaxFailUnexpectedInstruction => has_error = true,
+                else => |e| return e,
+            }
         };
     }
 
@@ -637,8 +638,8 @@ fn resolveRelocInner(
     subtractor: ?Relocation,
     code: []u8,
     macho_file: *MachO,
-    bw: *Writer,
-) Writer.Error!void {
+    writer: anytype,
+) ResolveError!void {
     const t = &macho_file.base.comp.root_mod.resolved_target.result;
     const cpu_arch = t.cpu.arch;
     const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;
@@ -652,7 +653,7 @@ fn resolveRelocInner(
     const divExact = struct {
         fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {
             return math.divExact(u12, num, den) catch {
-                try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {f} at offset 0x{x}", .{
+                try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {s} at offset 0x{x}", .{
                     atom.getName(ctx),
                     r.fmtPretty(ctx.getTarget().cpu.arch),
                     r.offset,
@@ -689,14 +690,14 @@ fn resolveRelocInner(
                 if (rel.tag == .@"extern") {
                     const sym = rel.getTargetSymbol(self, macho_file);
                     if (sym.isTlvInit(macho_file)) {
-                        try bw.writeInt(u64, @intCast(S - TLS), .little);
+                        try writer.writeInt(u64, @intCast(S - TLS), .little);
                         return;
                     }
                     if (sym.flags.import) return;
                 }
-                try bw.writeInt(u64, @bitCast(S + A - SUB), .little);
+                try writer.writeInt(u64, @bitCast(S + A - SUB), .little);
             } else if (rel.meta.length == 2) {
-                try bw.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little);
+                try writer.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little);
             } else unreachable;
         },
 
@@ -704,7 +705,7 @@ fn resolveRelocInner(
             assert(rel.tag == .@"extern");
             assert(rel.meta.length == 2);
             assert(rel.meta.pcrel);
-            try bw.writeInt(i32, @intCast(G + A - P), .little);
+            try writer.writeInt(i32, @intCast(G + A - P), .little);
         },
 
         .branch => {
@@ -713,7 +714,7 @@ fn resolveRelocInner(
             assert(rel.tag == .@"extern");
 
             switch (cpu_arch) {
-                .x86_64 => try bw.writeInt(i32, @intCast(S + A - P), .little),
+                .x86_64 => try writer.writeInt(i32, @intCast(S + A - P), .little),
                 .aarch64 => {
                     const disp: i28 = math.cast(i28, S + A - P) orelse blk: {
                         const thunk = self.getThunk(macho_file);
@@ -731,10 +732,10 @@ fn resolveRelocInner(
             assert(rel.meta.length == 2);
             assert(rel.meta.pcrel);
             if (rel.getTargetSymbol(self, macho_file).getSectionFlags().has_got) {
-                try bw.writeInt(i32, @intCast(G + A - P), .little);
+                try writer.writeInt(i32, @intCast(G + A - P), .little);
             } else {
                 try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file);
-                try bw.writeInt(i32, @intCast(S + A - P), .little);
+                try writer.writeInt(i32, @intCast(S + A - P), .little);
             }
         },
 
@@ -745,17 +746,17 @@ fn resolveRelocInner(
             const sym = rel.getTargetSymbol(self, macho_file);
             if (sym.getSectionFlags().tlv_ptr) {
                 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));
-                try bw.writeInt(i32, @intCast(S_ + A - P), .little);
+                try writer.writeInt(i32, @intCast(S_ + A - P), .little);
             } else {
                 try x86_64.relaxTlv(code[rel_offset - 3 ..], t);
-                try bw.writeInt(i32, @intCast(S + A - P), .little);
+                try writer.writeInt(i32, @intCast(S + A - P), .little);
             }
         },
 
         .signed, .signed1, .signed2, .signed4 => {
             assert(rel.meta.length == 2);
             assert(rel.meta.pcrel);
-            try bw.writeInt(i32, @intCast(S + A - P), .little);
+            try writer.writeInt(i32, @intCast(S + A - P), .little);
         },
 
         .page,
@@ -807,7 +808,7 @@ fn resolveRelocInner(
                     2 => try divExact(self, rel, @truncate(target), 4, macho_file),
                     3 => try divExact(self, rel, @truncate(target), 8, macho_file),
                 };
-                try bw.writeInt(u32, inst.toU32(), .little);
+                try writer.writeInt(u32, inst.toU32(), .little);
             }
         },
 
@@ -885,7 +886,7 @@ fn resolveRelocInner(
                     .sf = @as(u1, @truncate(reg_info.size)),
                 },
             };
-            try bw.writeInt(u32, inst.toU32(), .little);
+            try writer.writeInt(u32, inst.toU32(), .little);
         },
     }
 }
@@ -937,8 +938,11 @@ const x86_64 = struct {
     }
 
     fn encode(insts: []const Instruction, code: []u8) !void {
-        var bw: Writer = .fixed(code);
-        for (insts) |inst| try inst.encode(&bw, .{});
+        var stream = std.io.fixedBufferStream(code);
+        const writer = stream.writer();
+        for (insts) |inst| {
+            try inst.encode(writer, .{});
+        }
     }
 
     const bits = @import("../../arch/x86_64/bits.zig");
src/link/MachO/CodeSignature.zig
@@ -247,7 +247,7 @@ pub fn deinit(self: *CodeSignature, allocator: Allocator) void {
 pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void {
     const file = try fs.cwd().openFile(path, .{});
     defer file.close();
-    const inner = try file.readToEndAlloc(allocator, .unlimited);
+    const inner = try file.readToEndAlloc(allocator, std.math.maxInt(u32));
     self.entitlements = .{ .inner = inner };
 }
 
@@ -304,11 +304,10 @@ pub fn writeAdhocSignature(
     var hash: [hash_size]u8 = undefined;
 
     if (self.requirements) |*req| {
-        var aw: std.io.Writer.Allocating = .init(allocator);
-        defer aw.deinit();
-
-        try req.write(&aw.writer);
-        Sha256.hash(aw.getWritten(), &hash, .{});
+        var buf = std.ArrayList(u8).init(allocator);
+        defer buf.deinit();
+        try req.write(buf.writer());
+        Sha256.hash(buf.items, &hash, .{});
         self.code_directory.addSpecialHash(req.slotType(), hash);
 
         try blobs.append(.{ .requirements = req });
@@ -317,11 +316,10 @@ pub fn writeAdhocSignature(
     }
 
     if (self.entitlements) |*ents| {
-        var aw: std.io.Writer.Allocating = .init(allocator);
-        defer aw.deinit();
-
-        try ents.write(&aw.writer);
-        Sha256.hash(aw.getWritten(), &hash, .{});
+        var buf = std.ArrayList(u8).init(allocator);
+        defer buf.deinit();
+        try ents.write(buf.writer());
+        Sha256.hash(buf.items, &hash, .{});
         self.code_directory.addSpecialHash(ents.slotType(), hash);
 
         try blobs.append(.{ .entitlements = ents });
src/link/MachO/DebugSymbols.zig
@@ -269,14 +269,18 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
 
 fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } {
     const gpa = self.allocator;
-    var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeDsym(macho_file, self)));
-    defer gpa.free(bw.buffer);
+    const needed_size = load_commands.calcLoadCommandsSizeDsym(macho_file, self);
+    const buffer = try gpa.alloc(u8, needed_size);
+    defer gpa.free(buffer);
+
+    var stream = std.io.fixedBufferStream(buffer);
+    const writer = stream.writer();
 
     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 bw.writeStruct(self.uuid_cmd);
+    try writer.writeStruct(self.uuid_cmd);
     ncmds += 1;
 
     // Segment and section load commands
@@ -289,11 +293,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
             var out_seg = seg;
             out_seg.fileoff = 0;
             out_seg.filesize = 0;
-            try bw.writeStruct(out_seg);
+            try writer.writeStruct(out_seg);
             for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
                 var out_header = header;
                 out_header.offset = 0;
-                try bw.writeStruct(out_header);
+                try writer.writeStruct(out_header);
             }
             sect_id += seg.nsects;
         }
@@ -302,22 +306,23 @@ 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 bw.writeStruct(seg);
+            try writer.writeStruct(seg);
             for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
-                try bw.writeStruct(header);
+                try writer.writeStruct(header);
             }
             sect_id += seg.nsects;
         }
         ncmds += self.segments.items.len;
     }
 
-    try bw.writeStruct(self.symtab_cmd);
+    try writer.writeStruct(self.symtab_cmd);
     ncmds += 1;
 
-    assert(bw.end == bw.buffer.len);
-    try self.file.?.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
+    assert(stream.pos == needed_size);
+
+    try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
 
-    return .{ ncmds, bw.end };
+    return .{ ncmds, buffer.len };
 }
 
 fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
src/link/MachO/Dwarf.zig
@@ -81,7 +81,7 @@ pub const InfoReader = struct {
             .dwarf64 => 12,
         } + cuh_length;
         while (p.pos < end_pos) {
-            const di_code = try p.readLeb128(u64);
+            const di_code = try p.readUleb128(u64);
             if (di_code == 0) return error.UnexpectedEndOfFile;
             if (di_code == code) return;
 
@@ -174,14 +174,14 @@ pub const InfoReader = struct {
             dw.FORM.block1 => try p.readByte(),
             dw.FORM.block2 => try p.readInt(u16),
             dw.FORM.block4 => try p.readInt(u32),
-            dw.FORM.block => try p.readLeb128(u64),
+            dw.FORM.block => try p.readUleb128(u64),
             else => unreachable,
         };
         return p.readNBytes(len);
     }
 
     pub fn readExprLoc(p: *InfoReader) ![]const u8 {
-        const len: u64 = try p.readLeb128(u64);
+        const len: u64 = try p.readUleb128(u64);
         return p.readNBytes(len);
     }
 
@@ -191,8 +191,8 @@ pub const InfoReader = struct {
             dw.FORM.data2, dw.FORM.ref2 => try p.readInt(u16),
             dw.FORM.data4, dw.FORM.ref4 => try p.readInt(u32),
             dw.FORM.data8, dw.FORM.ref8, dw.FORM.ref_sig8 => try p.readInt(u64),
-            dw.FORM.udata, dw.FORM.ref_udata => try p.readLeb128(u64),
-            dw.FORM.sdata => @bitCast(try p.readLeb128(i64)),
+            dw.FORM.udata, dw.FORM.ref_udata => try p.readUleb128(u64),
+            dw.FORM.sdata => @bitCast(try p.readIleb128(i64)),
             else => return error.UnhandledConstantForm,
         };
     }
@@ -203,7 +203,7 @@ pub const InfoReader = struct {
             dw.FORM.strx2, dw.FORM.addrx2 => try p.readInt(u16),
             dw.FORM.strx3, dw.FORM.addrx3 => error.UnhandledForm,
             dw.FORM.strx4, dw.FORM.addrx4 => try p.readInt(u32),
-            dw.FORM.strx, dw.FORM.addrx => try p.readLeb128(u64),
+            dw.FORM.strx, dw.FORM.addrx => try p.readUleb128(u64),
             else => return error.UnhandledIndexForm,
         };
     }
@@ -272,10 +272,20 @@ pub const InfoReader = struct {
         };
     }
 
-    pub fn readLeb128(p: *InfoReader, comptime Type: type) !Type {
-        var r: std.io.Reader = .fixed(p.bytes()[p.pos..]);
-        defer p.pos += r.seek;
-        return r.takeLeb128(Type);
+    pub fn readUleb128(p: *InfoReader, comptime Type: type) !Type {
+        var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
+        var creader = std.io.countingReader(stream.reader());
+        const value: Type = try leb.readUleb128(Type, creader.reader());
+        p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
+        return value;
+    }
+
+    pub fn readIleb128(p: *InfoReader, comptime Type: type) !Type {
+        var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
+        var creader = std.io.countingReader(stream.reader());
+        const value: Type = try leb.readIleb128(Type, creader.reader());
+        p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
+        return value;
     }
 
     pub fn seekTo(p: *InfoReader, off: u64) !void {
@@ -297,10 +307,10 @@ pub const AbbrevReader = struct {
 
     pub fn readDecl(p: *AbbrevReader) !?AbbrevDecl {
         const pos = p.pos;
-        const code = try p.readLeb128(Code);
+        const code = try p.readUleb128(Code);
         if (code == 0) return null;
 
-        const tag = try p.readLeb128(Tag);
+        const tag = try p.readUleb128(Tag);
         const has_children = (try p.readByte()) > 0;
         return .{
             .code = code,
@@ -313,8 +323,8 @@ pub const AbbrevReader = struct {
 
     pub fn readAttr(p: *AbbrevReader) !?AbbrevAttr {
         const pos = p.pos;
-        const at = try p.readLeb128(At);
-        const form = try p.readLeb128(Form);
+        const at = try p.readUleb128(At);
+        const form = try p.readUleb128(Form);
         return if (at == 0 and form == 0) null else .{
             .at = at,
             .form = form,
@@ -329,10 +339,12 @@ pub const AbbrevReader = struct {
         return p.bytes()[p.pos];
     }
 
-    pub fn readLeb128(p: *AbbrevReader, comptime Type: type) !Type {
-        var r: std.io.Reader = .fixed(p.bytes()[p.pos..]);
-        defer p.pos += r.seek;
-        return r.takeLeb128(Type);
+    pub fn readUleb128(p: *AbbrevReader, comptime Type: type) !Type {
+        var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
+        var creader = std.io.countingReader(stream.reader());
+        const value: Type = try leb.readUleb128(Type, creader.reader());
+        p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
+        return value;
     }
 
     pub fn seekTo(p: *AbbrevReader, off: u64) !void {
src/link/MachO/Dylib.zig
@@ -158,6 +158,46 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
     }
 }
 
+const TrieIterator = struct {
+    data: []const u8,
+    pos: usize = 0,
+
+    fn getStream(it: *TrieIterator) std.io.FixedBufferStream([]const u8) {
+        return std.io.fixedBufferStream(it.data[it.pos..]);
+    }
+
+    fn readUleb128(it: *TrieIterator) !u64 {
+        var stream = it.getStream();
+        var creader = std.io.countingReader(stream.reader());
+        const reader = creader.reader();
+        const value = try std.leb.readUleb128(u64, reader);
+        it.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
+        return value;
+    }
+
+    fn readString(it: *TrieIterator) ![:0]const u8 {
+        var stream = it.getStream();
+        const reader = stream.reader();
+
+        var count: usize = 0;
+        while (true) : (count += 1) {
+            const byte = try reader.readByte();
+            if (byte == 0) break;
+        }
+
+        const str = @as([*:0]const u8, @ptrCast(it.data.ptr + it.pos))[0..count :0];
+        it.pos += count + 1;
+        return str;
+    }
+
+    fn readByte(it: *TrieIterator) !u8 {
+        var stream = it.getStream();
+        const value = try stream.reader().readByte();
+        it.pos += 1;
+        return value;
+    }
+};
+
 pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void {
     try self.exports.append(allocator, .{
         .name = try self.addString(allocator, name),
@@ -167,16 +207,16 @@ pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Ex
 
 fn parseTrieNode(
     self: *Dylib,
-    br: *std.io.Reader,
+    it: *TrieIterator,
     allocator: Allocator,
     arena: Allocator,
     prefix: []const u8,
 ) !void {
     const tracy = trace(@src());
     defer tracy.end();
-    const size = try br.takeLeb128(u64);
+    const size = try it.readUleb128();
     if (size > 0) {
-        const flags = try br.takeLeb128(u8);
+        const flags = try it.readUleb128();
         const kind = flags & macho.EXPORT_SYMBOL_FLAGS_KIND_MASK;
         const out_flags = Export.Flags{
             .abs = kind == macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE,
@@ -184,28 +224,29 @@ fn parseTrieNode(
             .weak = flags & macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION != 0,
         };
         if (flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT != 0) {
-            _ = try br.takeLeb128(u64); // dylib ordinal
-            const name = try br.takeSentinel(0);
+            _ = try it.readUleb128(); // dylib ordinal
+            const name = try it.readString();
             try self.addExport(allocator, if (name.len > 0) name else prefix, out_flags);
         } else if (flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER != 0) {
-            _ = try br.takeLeb128(u64); // stub offset
-            _ = try br.takeLeb128(u64); // resolver offset
+            _ = try it.readUleb128(); // stub offset
+            _ = try it.readUleb128(); // resolver offset
             try self.addExport(allocator, prefix, out_flags);
         } else {
-            _ = try br.takeLeb128(u64); // VM offset
+            _ = try it.readUleb128(); // VM offset
             try self.addExport(allocator, prefix, out_flags);
         }
     }
 
-    const nedges = try br.takeByte();
+    const nedges = try it.readByte();
+
     for (0..nedges) |_| {
-        const label = try br.takeSentinel(0);
-        const off = try br.takeLeb128(usize);
+        const label = try it.readString();
+        const off = try it.readUleb128();
         const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label });
-        const seek = br.seek;
-        br.seek = off;
-        try self.parseTrieNode(br, allocator, arena, prefix_label);
-        br.seek = seek;
+        const curr = it.pos;
+        it.pos = math.cast(usize, off) orelse return error.Overflow;
+        try self.parseTrieNode(it, allocator, arena, prefix_label);
+        it.pos = curr;
     }
 }
 
@@ -216,8 +257,8 @@ fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void {
     var arena = std.heap.ArenaAllocator.init(gpa);
     defer arena.deinit();
 
-    var r: std.io.Reader = .fixed(data);
-    try self.parseTrieNode(&r, gpa, arena.allocator(), "");
+    var it: TrieIterator = .{ .data = data };
+    try self.parseTrieNode(&it, gpa, arena.allocator(), "");
 }
 
 fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
src/link/MachO/eh_frame.zig
@@ -12,33 +12,36 @@ pub const Cie = struct {
         const tracy = trace(@src());
         defer tracy.end();
 
-        var r: std.io.Reader = .fixed(cie.getData(macho_file));
+        const data = cie.getData(macho_file);
+        const aug = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(data.ptr + 9)), 0);
 
-        try r.discard(9);
-        const aug = try r.takeSentinel(0);
         if (aug[0] != 'z') return; // TODO should we error out?
 
-        _ = try r.takeLeb128(u64); // code alignment factor
-        _ = try r.takeLeb128(u64); // data alignment factor
-        _ = try r.takeLeb128(u64); // return address register
-        _ = try r.takeLeb128(u64); // augmentation data length
+        var stream = std.io.fixedBufferStream(data[9 + aug.len + 1 ..]);
+        var creader = std.io.countingReader(stream.reader());
+        const reader = creader.reader();
+
+        _ = try leb.readUleb128(u64, reader); // code alignment factor
+        _ = try leb.readUleb128(u64, reader); // data alignment factor
+        _ = try leb.readUleb128(u64, reader); // return address register
+        _ = try leb.readUleb128(u64, reader); // augmentation data length
 
         for (aug[1..]) |ch| switch (ch) {
             'R' => {
-                const enc = try r.takeByte();
+                const enc = try reader.readByte();
                 if (enc != DW_EH_PE.pcrel | DW_EH_PE.absptr) {
                     @panic("unexpected pointer encoding"); // TODO error
                 }
             },
             'P' => {
-                const enc = try r.takeByte();
+                const enc = try reader.readByte();
                 if (enc != DW_EH_PE.pcrel | DW_EH_PE.indirect | DW_EH_PE.sdata4) {
                     @panic("unexpected personality pointer encoding"); // TODO error
                 }
-                _ = try r.takeInt(u32, .little); // personality pointer
+                _ = try reader.readInt(u32, .little); // personality pointer
             },
             'L' => {
-                const enc = try r.takeByte();
+                const enc = try reader.readByte();
                 switch (enc & DW_EH_PE.type_mask) {
                     DW_EH_PE.sdata4 => cie.lsda_size = .p32,
                     DW_EH_PE.absptr => cie.lsda_size = .p64,
@@ -125,16 +128,12 @@ pub const Fde = struct {
         const tracy = trace(@src());
         defer tracy.end();
 
+        const data = fde.getData(macho_file);
         const object = fde.getObject(macho_file);
         const sect = object.sections.items(.header)[object.eh_frame_sect_index.?];
 
-        var br: std.io.Reader = .fixed(fde.getData(macho_file));
-
-        try br.discard(4);
-        const cie_ptr = try br.takeInt(u32, .little);
-        const pc_begin = try br.takeInt(i64, .little);
-
         // Parse target atom index
+        const pc_begin = std.mem.readInt(i64, data[8..][0..8], .little);
         const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
         fde.atom = object.findAtom(taddr) orelse {
             try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
@@ -146,6 +145,7 @@ pub const Fde = struct {
         fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
 
         // Associate with a CIE
+        const cie_ptr = std.mem.readInt(u32, data[4..8], .little);
         const cie_offset = fde.offset + 4 - cie_ptr;
         const cie_index = for (object.cies.items, 0..) |cie, cie_index| {
             if (cie.offset == cie_offset) break @as(Cie.Index, @intCast(cie_index));
@@ -163,12 +163,14 @@ pub const Fde = struct {
 
         // Parse LSDA atom index if any
         if (cie.lsda_size) |lsda_size| {
-            try br.discard(8);
-            _ = try br.takeLeb128(u64); // augmentation length
-            fde.lsda_ptr_offset = @intCast(br.seek);
+            var stream = std.io.fixedBufferStream(data[24..]);
+            var creader = std.io.countingReader(stream.reader());
+            const reader = creader.reader();
+            _ = try leb.readUleb128(u64, reader); // augmentation length
+            fde.lsda_ptr_offset = @intCast(creader.bytes_read + 24);
             const lsda_ptr = switch (lsda_size) {
-                .p32 => try br.takeInt(i32, .little),
-                .p64 => try br.takeInt(i64, .little),
+                .p32 => try reader.readInt(i32, .little),
+                .p64 => try reader.readInt(i64, .little),
             };
             const lsda_addr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + fde.lsda_ptr_offset)) + lsda_ptr);
             fde.lsda = object.findAtom(lsda_addr) orelse {
@@ -209,35 +211,56 @@ pub const Fde = struct {
         return fde.getObject(macho_file).getAtom(fde.lsda);
     }
 
-    pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
+    pub fn format(
+        fde: Fde,
+        comptime unused_fmt_string: []const u8,
+        options: std.fmt.FormatOptions,
+        writer: anytype,
+    ) !void {
+        _ = fde;
+        _ = unused_fmt_string;
+        _ = options;
+        _ = writer;
+        @compileError("do not format FDEs directly");
+    }
+
+    pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(format2) {
         return .{ .data = .{
             .fde = fde,
             .macho_file = macho_file,
         } };
     }
 
-    const Format = struct {
+    const FormatContext = struct {
         fde: Fde,
         macho_file: *MachO,
-
-        fn default(f: Format, w: *Writer) Writer.Error!void {
-            const fde = f.fde;
-            const macho_file = f.macho_file;
-            try w.print("@{x} : size({x}) : cie({d}) : {s}", .{
-                fde.offset,
-                fde.getSize(),
-                fde.cie,
-                fde.getAtom(macho_file).getName(macho_file),
-            });
-            if (!fde.alive) try w.writeAll(" : [*]");
-        }
     };
 
+    fn format2(
+        ctx: FormatContext,
+        comptime unused_fmt_string: []const u8,
+        options: std.fmt.FormatOptions,
+        writer: anytype,
+    ) !void {
+        _ = unused_fmt_string;
+        _ = options;
+        const fde = ctx.fde;
+        const macho_file = ctx.macho_file;
+        try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
+            fde.offset,
+            fde.getSize(),
+            fde.cie,
+            fde.getAtom(macho_file).getName(macho_file),
+        });
+        if (!fde.alive) try writer.writeAll(" : [*]");
+    }
+
     pub const Index = u32;
 };
 
 pub const Iterator = struct {
-    reader: *std.io.Reader,
+    data: []const u8,
+    pos: u32 = 0,
 
     pub const Record = struct {
         tag: enum { fde, cie },
@@ -246,19 +269,21 @@ pub const Iterator = struct {
     };
 
     pub fn next(it: *Iterator) !?Record {
-        const r = it.reader;
-        if (r.seek >= r.storageBuffer().len) return null;
+        if (it.pos >= it.data.len) return null;
+
+        var stream = std.io.fixedBufferStream(it.data[it.pos..]);
+        const reader = stream.reader();
 
-        const size = try r.takeInt(u32, .little);
+        const size = try reader.readInt(u32, .little);
         if (size == 0xFFFFFFFF) @panic("DWARF CFI is 32bit on macOS");
 
-        const id = try r.takeInt(u32, .little);
-        const record: Record = .{
+        const id = try reader.readInt(u32, .little);
+        const record = Record{
             .tag = if (id == 0) .cie else .fde,
-            .offset = @intCast(r.seek),
+            .offset = it.pos,
             .size = size,
         };
-        try r.discard(size);
+        it.pos += size + 4;
 
         return record;
     }
src/link/MachO/file.zig
@@ -321,11 +321,11 @@ pub const File = union(enum) {
         };
     }
 
-    pub fn writeAr(file: File, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) Writer.Error!void {
+    pub fn writeAr(file: File, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
         return switch (file) {
             .dylib, .internal => unreachable,
-            .zig_object => |x| x.writeAr(bw, ar_format),
-            .object => |x| x.writeAr(bw, ar_format, macho_file),
+            .zig_object => |x| x.writeAr(ar_format, writer),
+            .object => |x| x.writeAr(ar_format, macho_file, writer),
         };
     }
 
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.print(gpa, "{s}\x00", .{methname}) catch unreachable;
+    self.objc_methnames.writer(gpa).print("{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
@@ -181,20 +181,23 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
     return offset;
 }
 
-pub fn writeDylinkerLC(bw: *Writer) Writer.Error!void {
+pub fn writeDylinkerLC(writer: anytype) !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 bw.writeStruct(macho.dylinker_command{
+    try writer.writeStruct(macho.dylinker_command{
         .cmd = .LOAD_DYLINKER,
         .cmdsize = cmdsize,
         .name = @sizeOf(macho.dylinker_command),
     });
-    try bw.writeAll(mem.sliceTo(default_dyld_path, 0));
-    try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylinker_command) - name_len);
+    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);
+    }
 }
 
 const WriteDylibLCCtx = struct {
@@ -205,14 +208,14 @@ const WriteDylibLCCtx = struct {
     compatibility_version: u32 = 0x10000,
 };
 
-pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {
+pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
     const name_len = ctx.name.len + 1;
-    const cmdsize: u32 = @intCast(mem.alignForward(
+    const cmdsize = @as(u32, @intCast(mem.alignForward(
         u64,
         @sizeOf(macho.dylib_command) + name_len,
         @sizeOf(u64),
-    ));
-    try bw.writeStruct(macho.dylib_command{
+    )));
+    try writer.writeStruct(macho.dylib_command{
         .cmd = ctx.cmd,
         .cmdsize = cmdsize,
         .dylib = .{
@@ -222,9 +225,12 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {
             .compatibility_version = ctx.compatibility_version,
         },
     });
-    try bw.writeAll(ctx.name);
-    try bw.writeByte(0);
-    try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylib_command) - name_len);
+    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);
+    }
 }
 
 pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
@@ -253,23 +259,26 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
     }, writer);
 }
 
-pub fn writeRpathLC(bw: *Writer, rpath: []const u8) !void {
+pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {
     const rpath_len = rpath.len + 1;
     const cmdsize = @as(u32, @intCast(mem.alignForward(
         u64,
         @sizeOf(macho.rpath_command) + rpath_len,
         @sizeOf(u64),
     )));
-    try bw.writeStruct(macho.rpath_command{
+    try writer.writeStruct(macho.rpath_command{
         .cmdsize = cmdsize,
         .path = @sizeOf(macho.rpath_command),
     });
-    try bw.writeAll(rpath);
-    try bw.writeByte(0);
-    try bw.splatByteAll(0, cmdsize - @sizeOf(macho.rpath_command) - rpath_len);
+    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);
+    }
 }
 
-pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) Writer.Error!void {
+pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {
     const cmd: macho.LC = switch (platform.os_tag) {
         .macos => .VERSION_MIN_MACOSX,
         .ios => .VERSION_MIN_IPHONEOS,
@@ -277,7 +286,7 @@ pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?st
         .watchos => .VERSION_MIN_WATCHOS,
         else => unreachable,
     };
-    try bw.writeAll(mem.asBytes(&macho.version_min_command{
+    try writer.writeAll(mem.asBytes(&macho.version_min_command{
         .cmd = cmd,
         .version = platform.toAppleVersion(),
         .sdk = if (sdk_version) |ver|
@@ -287,9 +296,9 @@ pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?st
     }));
 }
 
-pub fn writeBuildVersionLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) Writer.Error!void {
+pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {
     const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
-    try bw.writeStruct(macho.build_version_command{
+    try writer.writeStruct(macho.build_version_command{
         .cmdsize = cmdsize,
         .platform = platform.toApplePlatform(),
         .minos = platform.toAppleVersion(),
@@ -299,7 +308,7 @@ pub fn writeBuildVersionLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?
             platform.toAppleVersion(),
         .ntools = 1,
     });
-    try bw.writeAll(mem.asBytes(&macho.build_tool_version{
+    try writer.writeAll(mem.asBytes(&macho.build_tool_version{
         .tool = .ZIG,
         .version = 0x0,
     }));
src/link/MachO/Object.zig
@@ -1069,7 +1069,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi
         }
     }
 
-    var it: eh_frame.Iterator = .{ .br = .fixed(self.eh_frame_data.items) };
+    var it = eh_frame.Iterator{ .data = self.eh_frame_data.items };
     while (try it.next()) |rec| {
         switch (rec.tag) {
             .cie => try self.cies.append(allocator, .{
@@ -1698,11 +1698,11 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
     };
 }
 
-pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) !void {
+pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
     // Header
     const size = try macho_file.cast(usize, self.output_ar_state.size);
     const basename = std.fs.path.basename(self.path.sub_path);
-    try Archive.writeHeader(bw, basename, size, ar_format);
+    try Archive.writeHeader(basename, size, ar_format, writer);
     // Data
     const file = macho_file.getFileHandle(self.file_handle);
     // TODO try using copyRangeAll
@@ -1711,7 +1711,7 @@ pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file:
     defer gpa.free(data);
     const amt = try file.preadAll(data, self.offset);
     if (amt != size) return error.InputOutput;
-    try bw.writeAll(data);
+    try writer.writeAll(data);
 }
 
 pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
@@ -1865,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
         }
         gpa.free(sections_data);
     }
-    @memset(sections_data, &.{});
+    @memset(sections_data, &[0]u8{});
     const file = macho_file.getFileHandle(self.file_handle);
 
     for (headers, 0..) |header, n_sect| {
src/link/MachO/relocatable.zig
@@ -202,30 +202,38 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
     };
 
     if (build_options.enable_logging) {
-        state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
+        state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(macho_file)});
     }
 
-    var bw: Writer = .fixed(try gpa.alloc(u8, total_size));
-    defer gpa.free(bw.buffer);
+    var buffer = std.ArrayList(u8).init(gpa);
+    defer buffer.deinit();
+    try buffer.ensureTotalCapacityPrecise(total_size);
+    const writer = buffer.writer();
 
     // Write magic
-    bw.writeAll(Archive.ARMAG) catch unreachable;
+    try writer.writeAll(Archive.ARMAG);
 
     // Write symtab
-    ar_symtab.write(&bw, format, macho_file) catch |err| {
-        return diags.fail("failed to write archive symbol table: {s}", .{@errorName(err)});
+    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)}),
     };
 
     // Write object files
     for (files.items) |index| {
-        bw.splatByteAll(0, mem.alignForward(usize, bw.end, 2) - bw.end) catch unreachable;
-        macho_file.getFile(index).?.writeAr(&bw, format, macho_file) catch |err|
+        const aligned = mem.alignForward(usize, buffer.items.len, 2);
+        const padding = aligned - buffer.items.len;
+        if (padding > 0) {
+            try writer.writeByteNTimes(0, padding);
+        }
+        macho_file.getFile(index).?.writeAr(format, macho_file, writer) catch |err|
             return diags.fail("failed to write archive: {s}", .{@errorName(err)});
     }
 
-    assert(bw.end == bw.buffer.len);
-    try macho_file.setEndPos(bw.end);
-    try macho_file.pwriteAll(bw.buffer, 0);
+    assert(buffer.items.len == total_size);
+
+    try macho_file.setEndPos(total_size);
+    try macho_file.pwriteAll(buffer.items, 0);
 
     if (diags.hasErrors()) return error.LinkFailure;
 }
@@ -664,7 +672,7 @@ fn writeCompactUnwindWorker(macho_file: *MachO, object: *Object) void {
         diags.addError("failed to write '__LD,__eh_frame' section: {s}", .{@errorName(err)});
 }
 
-fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {
+fn writeSectionsToFile(macho_file: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
 
@@ -681,8 +689,12 @@ fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {
 
 fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } {
     const gpa = macho_file.base.comp.gpa;
-    var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeObject(macho_file)));
-    defer gpa.free(bw.buffer);
+    const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file);
+    const buffer = try gpa.alloc(u8, needed_size);
+    defer gpa.free(buffer);
+
+    var stream = std.io.fixedBufferStream(buffer);
+    const writer = stream.writer();
 
     var ncmds: usize = 0;
 
@@ -690,31 +702,47 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
     {
         assert(macho_file.segments.items.len == 1);
         const seg = macho_file.segments.items[0];
-        bw.writeStruct(seg) catch unreachable;
+        writer.writeStruct(seg) catch |err| switch (err) {
+            error.NoSpaceLeft => unreachable,
+        };
         for (macho_file.sections.items(.header)) |header| {
-            bw.writeStruct(header) catch unreachable;
+            writer.writeStruct(header) catch |err| switch (err) {
+                error.NoSpaceLeft => unreachable,
+            };
         }
         ncmds += 1;
     }
 
-    bw.writeStruct(macho_file.data_in_code_cmd) catch unreachable;
+    writer.writeStruct(macho_file.data_in_code_cmd) catch |err| switch (err) {
+        error.NoSpaceLeft => unreachable,
+    };
     ncmds += 1;
-    bw.writeStruct(macho_file.symtab_cmd) catch unreachable;
+    writer.writeStruct(macho_file.symtab_cmd) catch |err| switch (err) {
+        error.NoSpaceLeft => unreachable,
+    };
     ncmds += 1;
-    bw.writeStruct(macho_file.dysymtab_cmd) catch unreachable;
+    writer.writeStruct(macho_file.dysymtab_cmd) catch |err| switch (err) {
+        error.NoSpaceLeft => unreachable,
+    };
     ncmds += 1;
 
     if (macho_file.platform.isBuildVersionCompatible()) {
-        load_commands.writeBuildVersionLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable;
+        load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
+            error.NoSpaceLeft => unreachable,
+        };
         ncmds += 1;
     } else {
-        load_commands.writeVersionMinLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable;
+        load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
+            error.NoSpaceLeft => unreachable,
+        };
         ncmds += 1;
     }
 
-    assert(bw.end == bw.buffer.len);
-    try macho_file.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
-    return .{ ncmds, bw.end };
+    assert(stream.pos == needed_size);
+
+    try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
+
+    return .{ ncmds, buffer.len };
 }
 
 fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
src/link/MachO/Symbol.zig
@@ -297,7 +297,7 @@ const Format = struct {
     symbol: Symbol,
     macho_file: *MachO,
 
-    fn format2(f: Format, w: *Writer) Writer.Error!void {
+    fn default(f: Format, w: *Writer) Writer.Error!void {
         const symbol = f.symbol;
         try w.print("%{d} : {s} : @{x}", .{
             symbol.nlist_idx,
src/link/MachO/synthetic.zig
@@ -27,13 +27,13 @@ pub const GotSection = struct {
         return got.symbols.items.len * @sizeOf(u64);
     }
 
-    pub fn write(got: GotSection, macho_file: *MachO, bw: *Writer) !void {
+    pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void {
         const tracy = trace(@src());
         defer tracy.end();
         for (got.symbols.items) |ref| {
             const sym = ref.getSymbol(macho_file).?;
             const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file);
-            try bw.writeInt(u64, value, .little);
+            try writer.writeInt(u64, value, .little);
         }
     }
 
@@ -89,7 +89,7 @@ pub const StubsSection = struct {
         return stubs.symbols.items.len * header.reserved2;
     }
 
-    pub fn write(stubs: StubsSection, macho_file: *MachO, bw: *Writer) !void {
+    pub fn write(stubs: StubsSection, macho_file: *MachO, writer: anytype) !void {
         const tracy = trace(@src());
         defer tracy.end();
         const cpu_arch = macho_file.getTarget().cpu.arch;
@@ -101,20 +101,20 @@ pub const StubsSection = struct {
             const target = laptr_sect.addr + idx * @sizeOf(u64);
             switch (cpu_arch) {
                 .x86_64 => {
-                    try bw.writeAll(&.{ 0xff, 0x25 });
-                    try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little);
+                    try writer.writeAll(&.{ 0xff, 0x25 });
+                    try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
                 },
                 .aarch64 => {
                     // TODO relax if possible
                     const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
-                    try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
+                    try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
                     const off = try math.divExact(u12, @truncate(target), 8);
-                    try bw.writeInt(
+                    try writer.writeInt(
                         u32,
                         aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
                         .little,
                     );
-                    try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
+                    try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
                 },
                 else => unreachable,
             }
@@ -175,11 +175,11 @@ pub const StubsHelperSection = struct {
         return s;
     }
 
-    pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void {
+    pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
-        try stubs_helper.writePreamble(macho_file, bw);
+        try stubs_helper.writePreamble(macho_file, writer);
 
         const cpu_arch = macho_file.getTarget().cpu.arch;
         const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
@@ -195,24 +195,24 @@ pub const StubsHelperSection = struct {
             const target: i64 = @intCast(sect.addr);
             switch (cpu_arch) {
                 .x86_64 => {
-                    try bw.writeByte(0x68);
-                    try bw.writeInt(u32, offset, .little);
-                    try bw.writeByte(0xe9);
-                    try bw.writeInt(i32, @intCast(target - source - 6 - 4), .little);
+                    try writer.writeByte(0x68);
+                    try writer.writeInt(u32, offset, .little);
+                    try writer.writeByte(0xe9);
+                    try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);
                 },
                 .aarch64 => {
                     const literal = blk: {
                         const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);
                         break :blk std.math.cast(u18, div_res) orelse return error.Overflow;
                     };
-                    try bw.writeInt(u32, aarch64.Instruction.ldrLiteral(
+                    try writer.writeInt(u32, aarch64.Instruction.ldrLiteral(
                         .w16,
                         literal,
                     ).toU32(), .little);
                     const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse
                         return error.Overflow;
-                    try bw.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
-                    try bw.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
+                    try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
+                    try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
                 },
                 else => unreachable,
             }
@@ -220,7 +220,7 @@ pub const StubsHelperSection = struct {
         }
     }
 
-    fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void {
+    fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
         _ = stubs_helper;
         const obj = macho_file.getInternalObject().?;
         const cpu_arch = macho_file.getTarget().cpu.arch;
@@ -235,21 +235,21 @@ pub const StubsHelperSection = struct {
         };
         switch (cpu_arch) {
             .x86_64 => {
-                try bw.writeAll(&.{ 0x4c, 0x8d, 0x1d });
-                try bw.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);
-                try bw.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
-                try bw.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);
-                try bw.writeByte(0x90);
+                try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d });
+                try writer.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);
+                try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
+                try writer.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);
+                try writer.writeByte(0x90);
             },
             .aarch64 => {
                 {
                     // TODO relax if possible
                     const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));
-                    try bw.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
+                    try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
                     const off: u12 = @truncate(dyld_private_addr);
-                    try bw.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
+                    try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
                 }
-                try bw.writeInt(u32, aarch64.Instruction.stp(
+                try writer.writeInt(u32, aarch64.Instruction.stp(
                     .x16,
                     .x17,
                     aarch64.Register.sp,
@@ -258,15 +258,15 @@ pub const StubsHelperSection = struct {
                 {
                     // TODO relax if possible
                     const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));
-                    try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
+                    try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
                     const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);
-                    try bw.writeInt(u32, aarch64.Instruction.ldr(
+                    try writer.writeInt(u32, aarch64.Instruction.ldr(
                         .x16,
                         .x16,
                         aarch64.Instruction.LoadStoreOffset.imm(off),
                     ).toU32(), .little);
                 }
-                try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
+                try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
             },
             else => unreachable,
         }
@@ -279,7 +279,7 @@ pub const LaSymbolPtrSection = struct {
         return macho_file.stubs.symbols.items.len * @sizeOf(u64);
     }
 
-    pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, bw: *Writer) !void {
+    pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void {
         const tracy = trace(@src());
         defer tracy.end();
         _ = laptr;
@@ -290,12 +290,12 @@ pub const LaSymbolPtrSection = struct {
             const sym = ref.getSymbol(macho_file).?;
             if (sym.flags.weak) {
                 const value = sym.getAddress(.{ .stubs = false }, macho_file);
-                try bw.writeInt(u64, @intCast(value), .little);
+                try writer.writeInt(u64, @intCast(value), .little);
             } else {
                 const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) +
                     StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx;
                 stub_helper_idx += 1;
-                try bw.writeInt(u64, @intCast(value), .little);
+                try writer.writeInt(u64, @intCast(value), .little);
             }
         }
     }
@@ -329,16 +329,16 @@ pub const TlvPtrSection = struct {
         return tlv.symbols.items.len * @sizeOf(u64);
     }
 
-    pub fn write(tlv: TlvPtrSection, macho_file: *MachO, bw: *Writer) !void {
+    pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
         for (tlv.symbols.items) |ref| {
             const sym = ref.getSymbol(macho_file).?;
             if (sym.flags.import) {
-                try bw.writeInt(u64, 0, .little);
+                try writer.writeInt(u64, 0, .little);
             } else {
-                try bw.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
+                try writer.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
             }
         }
     }
@@ -400,7 +400,7 @@ pub const ObjcStubsSection = struct {
         return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
     }
 
-    pub fn write(objc: ObjcStubsSection, macho_file: *MachO, bw: *Writer) !void {
+    pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: anytype) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
@@ -411,18 +411,18 @@ pub const ObjcStubsSection = struct {
             const addr = objc.getAddress(@intCast(idx), macho_file);
             switch (macho_file.getTarget().cpu.arch) {
                 .x86_64 => {
-                    try bw.writeAll(&.{ 0x48, 0x8b, 0x35 });
+                    try writer.writeAll(&.{ 0x48, 0x8b, 0x35 });
                     {
                         const target = sym.getObjcSelrefsAddress(macho_file);
                         const source = addr;
-                        try bw.writeInt(i32, @intCast(target - source - 3 - 4), .little);
+                        try writer.writeInt(i32, @intCast(target - source - 3 - 4), .little);
                     }
-                    try bw.writeAll(&.{ 0xff, 0x25 });
+                    try writer.writeAll(&.{ 0xff, 0x25 });
                     {
                         const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
                         const target = target_sym.getGotAddress(macho_file);
                         const source = addr + 7;
-                        try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little);
+                        try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
                     }
                 },
                 .aarch64 => {
@@ -430,9 +430,9 @@ pub const ObjcStubsSection = struct {
                         const target = sym.getObjcSelrefsAddress(macho_file);
                         const source = addr;
                         const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
-                        try bw.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
+                        try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
                         const off = try math.divExact(u12, @truncate(target), 8);
-                        try bw.writeInt(
+                        try writer.writeInt(
                             u32,
                             aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
                             .little,
@@ -443,18 +443,18 @@ pub const ObjcStubsSection = struct {
                         const target = target_sym.getGotAddress(macho_file);
                         const source = addr + 2 * @sizeOf(u32);
                         const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
-                        try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
+                        try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
                         const off = try math.divExact(u12, @truncate(target), 8);
-                        try bw.writeInt(
+                        try writer.writeInt(
                             u32,
                             aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
                             .little,
                         );
                     }
-                    try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
-                    try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
-                    try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
-                    try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
+                    try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
+                    try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
+                    try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
+                    try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
                 },
                 else => unreachable,
             }
@@ -496,7 +496,7 @@ pub const Indsymtab = struct {
         macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
     }
 
-    pub fn write(ind: Indsymtab, macho_file: *MachO, bw: *Writer) !void {
+    pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void {
         const tracy = trace(@src());
         defer tracy.end();
 
@@ -505,21 +505,21 @@ pub const Indsymtab = struct {
         for (macho_file.stubs.symbols.items) |ref| {
             const sym = ref.getSymbol(macho_file).?;
             if (sym.getOutputSymtabIndex(macho_file)) |idx| {
-                try bw.writeInt(u32, idx, .little);
+                try writer.writeInt(u32, idx, .little);
             }
         }
 
         for (macho_file.got.symbols.items) |ref| {
             const sym = ref.getSymbol(macho_file).?;
             if (sym.getOutputSymtabIndex(macho_file)) |idx| {
-                try bw.writeInt(u32, idx, .little);
+                try writer.writeInt(u32, idx, .little);
             }
         }
 
         for (macho_file.stubs.symbols.items) |ref| {
             const sym = ref.getSymbol(macho_file).?;
             if (sym.getOutputSymtabIndex(macho_file)) |idx| {
-                try bw.writeInt(u32, idx, .little);
+                try writer.writeInt(u32, idx, .little);
             }
         }
     }
@@ -573,7 +573,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, bw: *Writer) !void {
+    pub fn write(dice: DataInCode, macho_file: *MachO, writer: anytype) !void {
         const base_address = if (!macho_file.base.isRelocatable())
             macho_file.getTextSegment().vmaddr
         else
@@ -581,7 +581,7 @@ 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 bw.writeStruct(macho.data_in_code_entry{
+            try writer.writeStruct(macho.data_in_code_entry{
                 .offset = @intCast(offset),
                 .length = entry.length,
                 .kind = entry.kind,
src/link/MachO/Thunk.zig
@@ -20,16 +20,16 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
     return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;
 }
 
-pub fn write(thunk: Thunk, macho_file: *MachO, bw: *Writer) !void {
+pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
     for (thunk.symbols.keys(), 0..) |ref, i| {
         const sym = ref.getSymbol(macho_file).?;
         const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
         const taddr = sym.getAddress(.{}, macho_file);
         const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
-        try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
+        try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
         const off: u12 = @truncate(taddr);
-        try bw.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
-        try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
+        try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
+        try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
     }
 }
 
src/link/MachO/UnwindInfo.zig
@@ -289,10 +289,13 @@ pub fn calcSize(info: UnwindInfo) usize {
     return total_size;
 }
 
-pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!void {
+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();
+
     const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);
     const common_encodings_count: u32 = info.common_encodings_count;
     const personalities_offset: u32 = common_encodings_offset + common_encodings_count * @sizeOf(u32);
@@ -300,7 +303,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
     const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);
     const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));
 
-    try bw.writeStruct(macho.unwind_info_section_header{
+    try writer.writeStruct(macho.unwind_info_section_header{
         .commonEncodingsArraySectionOffset = common_encodings_offset,
         .commonEncodingsArrayCount = common_encodings_count,
         .personalityArraySectionOffset = personalities_offset,
@@ -309,11 +312,11 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
         .indexCount = indexes_count,
     });
 
-    try bw.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));
+    try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));
 
     for (info.personalities[0..info.personalities_count]) |ref| {
         const sym = ref.getSymbol(macho_file).?;
-        try bw.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little);
+        try writer.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little);
     }
 
     const pages_base_offset = @as(u32, @intCast(header.size - (info.pages.items.len * second_level_page_bytes)));
@@ -322,7 +325,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
     for (info.pages.items, 0..) |page, i| {
         assert(page.count > 0);
         const rec = info.records.items[page.start].getUnwindRecord(macho_file);
-        try bw.writeStruct(macho.unwind_info_section_header_index_entry{
+        try writer.writeStruct(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 +
@@ -332,7 +335,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
 
     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 bw.writeStruct(macho.unwind_info_section_header_index_entry{
+    try writer.writeStruct(macho.unwind_info_section_header_index_entry{
         .functionOffset = sentinel_address,
         .secondLevelPagesSectionOffset = 0,
         .lsdaIndexArraySectionOffset = lsda_base_offset +
@@ -341,20 +344,23 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
 
     for (info.lsdas.items) |index| {
         const rec = info.records.items[index].getUnwindRecord(macho_file);
-        try bw.writeStruct(macho.unwind_info_section_header_lsda_index_entry{
+        try writer.writeStruct(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)),
         });
     }
 
     for (info.pages.items) |page| {
-        const start = bw.count;
-        try page.write(info, macho_file, bw);
-        const nwritten = bw.count - start;
-        try bw.splatByteAll(0, math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow);
+        const start = stream.pos;
+        try page.write(info, macho_file, writer);
+        const nwritten = stream.pos - 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);
+        }
     }
 
-    @memset(bw.unusedCapacitySlice(), 0);
+    @memset(buffer[stream.pos..], 0);
 }
 
 fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {
src/link/MachO/ZigObject.zig
@@ -317,12 +317,12 @@ pub fn updateArSize(self: *ZigObject) void {
     self.output_ar_state.size = self.data.items.len;
 }
 
-pub fn writeAr(self: ZigObject, bw: *Writer, ar_format: Archive.Format) Writer.Error!void {
+pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void {
     // Header
     const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
-    try Archive.writeHeader(bw, self.basename, size, ar_format);
+    try Archive.writeHeader(self.basename, size, ar_format, writer);
     // Data
-    try bw.writeAll(self.data.items);
+    try writer.writeAll(self.data.items);
 }
 
 pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void {
@@ -884,6 +884,7 @@ pub fn updateNav(
                 defer debug_wip_nav.deinit();
                 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
                     error.OutOfMemory => return error.OutOfMemory,
+                    error.Overflow => return error.Overflow,
                     else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
                 };
             }
@@ -920,6 +921,7 @@ pub fn updateNav(
 
         if (debug_wip_nav) |*wip_nav| self.dwarf.?.finishWipNav(pt, nav_index, wip_nav) catch |err| switch (err) {
             error.OutOfMemory => return error.OutOfMemory,
+            error.Overflow => return error.Overflow,
             else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
         };
     } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index);
src/link/MachO.zig
@@ -41,9 +41,9 @@ data_in_code_cmd: macho.linkedit_data_command = .{ .cmd = .DATA_IN_CODE },
 uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },
 codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },
 
-pagezero_seg_index: ?u4 = null,
-text_seg_index: ?u4 = null,
-linkedit_seg_index: ?u4 = null,
+pagezero_seg_index: ?u8 = null,
+text_seg_index: ?u8 = null,
+linkedit_seg_index: ?u8 = null,
 text_sect_index: ?u8 = null,
 data_sect_index: ?u8 = null,
 got_sect_index: ?u8 = null,
@@ -76,10 +76,10 @@ unwind_info: UnwindInfo = .{},
 data_in_code: DataInCode = .{},
 
 /// Tracked loadable segments during incremental linking.
-zig_text_seg_index: ?u4 = null,
-zig_const_seg_index: ?u4 = null,
-zig_data_seg_index: ?u4 = null,
-zig_bss_seg_index: ?u4 = null,
+zig_text_seg_index: ?u8 = null,
+zig_const_seg_index: ?u8 = null,
+zig_data_seg_index: ?u8 = null,
+zig_bss_seg_index: ?u8 = null,
 
 /// Tracked section headers with incremental updates to Zig object.
 zig_text_sect_index: ?u8 = null,
@@ -591,7 +591,6 @@ pub fn flush(
         error.NoSpaceLeft => unreachable,
         error.OutOfMemory => return error.OutOfMemory,
         error.LinkFailure => return error.LinkFailure,
-        else => unreachable,
     };
     try self.writeHeader(ncmds, sizeofcmds);
     self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) {
@@ -1075,7 +1074,7 @@ fn accessLibPath(
 
     for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
         test_path.clearRetainingCapacity();
-        try test_path.print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
+        try test_path.writer().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,
@@ -1098,7 +1097,7 @@ fn accessFrameworkPath(
 
     for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
         test_path.clearRetainingCapacity();
-        try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
+        try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
             search_dir,
             name,
             name,
@@ -1179,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.print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
+                            try test_path.writer().print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
                         } else {
-                            try test_path.print("{s}{s}", .{ path, ext });
+                            try test_path.writer().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) {
@@ -2132,7 +2131,7 @@ fn initSegments(self: *MachO) !void {
 
     mem.sort(Entry, entries.items, self, Entry.lessThan);
 
-    const backlinks = try gpa.alloc(u4, entries.items.len);
+    const backlinks = try gpa.alloc(u8, entries.items.len);
     defer gpa.free(backlinks);
     for (entries.items, 0..) |entry, i| {
         backlinks[entry.index] = @intCast(i);
@@ -2146,7 +2145,7 @@ fn initSegments(self: *MachO) !void {
         self.segments.appendAssumeCapacity(segments[sorted.index]);
     }
 
-    for (&[_]*?u4{
+    for (&[_]*?u8{
         &self.pagezero_seg_index,
         &self.text_seg_index,
         &self.linkedit_seg_index,
@@ -2164,7 +2163,7 @@ fn initSegments(self: *MachO) !void {
     for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| {
         const segname = header.segName();
         const segment_id = self.getSegmentByName(segname) orelse blk: {
-            const segment_id: u4 = @intCast(self.segments.items.len);
+            const segment_id = @as(u8, @intCast(self.segments.items.len));
             const protection = getSegmentProt(segname);
             try self.segments.append(gpa, .{
                 .cmdsize = @sizeOf(macho.segment_command_64),
@@ -2527,8 +2526,10 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
 
     const doWork = struct {
         fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
-            var bw: Writer = .fixed(buffer[try macho_file.cast(usize, th.value)..][0..th.size()]);
-            try th.write(macho_file, &bw);
+            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());
         }
     }.doWork;
     const out = self.sections.items(.out)[thunk.out_n_sect].items;
@@ -2555,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 bw: Writer = .fixed(buffer);
+            var stream = std.io.fixedBufferStream(buffer);
             switch (tag) {
                 .eh_frame => eh_frame.write(macho_file, buffer),
-                .unwind_info => try macho_file.unwind_info.write(macho_file, &bw),
-                .got => try macho_file.got.write(macho_file, &bw),
-                .stubs => try macho_file.stubs.write(macho_file, &bw),
-                .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, &bw),
-                .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, &bw),
-                .objc_stubs => try macho_file.objc_stubs.write(macho_file, &bw),
+                .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()),
             }
         }
     }.doWork;
@@ -2604,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 bw: Writer = .fixed(out.items);
-            try macho_file.stubs_helper.write(macho_file, &bw);
+            var stream = std.io.fixedBufferStream(out.items);
+            try macho_file.stubs_helper.write(macho_file, stream.writer());
         }
     }.doWork;
     doWork(self) catch |err|
@@ -2664,49 +2665,46 @@ fn writeDyldInfo(self: *MachO) !void {
     needed_size += cmd.lazy_bind_size;
     needed_size += cmd.export_size;
 
-    var bw: Writer = .fixed(try gpa.alloc(u8, needed_size));
-    defer gpa.free(bw.buffer);
-    @memset(bw.buffer, 0);
+    const buffer = try gpa.alloc(u8, needed_size);
+    defer gpa.free(buffer);
+    @memset(buffer, 0);
 
-    try self.rebase_section.write(&bw);
-    bw.end = cmd.bind_off - base_off;
-    try self.bind_section.write(&bw);
-    bw.end = cmd.weak_bind_off - base_off;
-    try self.weak_bind_section.write(&bw);
-    bw.end = cmd.lazy_bind_off - base_off;
-    try self.lazy_bind_section.write(&bw);
-    bw.end = cmd.export_off - base_off;
-    try self.export_trie.write(&bw);
-    try self.pwriteAll(bw.buffer, cmd.rebase_off);
+    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);
+    try self.pwriteAll(buffer, cmd.rebase_off);
 }
 
-pub fn writeDataInCode(self: *MachO) link.File.FlushError!void {
+pub fn writeDataInCode(self: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
     const gpa = self.base.comp.gpa;
     const cmd = self.data_in_code_cmd;
-
-    var bw: Writer = .fixed(try gpa.alloc(u8, self.data_in_code.size()));
-    defer gpa.free(bw.buffer);
-
-    try self.data_in_code.write(self, &bw);
-    assert(bw.end == bw.buffer.len);
-    try self.pwriteAll(bw.buffer, cmd.dataoff);
+    var buffer = try std.ArrayList(u8).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);
 }
 
 fn writeIndsymtab(self: *MachO) !void {
     const tracy = trace(@src());
     defer tracy.end();
-
     const gpa = self.base.comp.gpa;
     const cmd = self.dysymtab_cmd;
-
-    var bw: Writer = .fixed(try gpa.alloc(u8, @sizeOf(u32) * cmd.nindirectsyms));
-    defer gpa.free(bw.buffer);
-
-    try self.indsymtab.write(self, &bw);
-    assert(bw.end == bw.buffer.len);
-    try self.pwriteAll(bw.buffer, cmd.indirectsymoff);
+    const needed_size = cmd.nindirectsyms * @sizeOf(u32);
+    var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size);
+    defer buffer.deinit();
+    try self.indsymtab.write(self, buffer.writer());
+    try self.pwriteAll(buffer.items, cmd.indirectsymoff);
 }
 
 pub fn writeSymtabToFile(self: *MachO) !void {
@@ -2816,12 +2814,15 @@ fn calcSymtabSize(self: *MachO) !void {
     }
 }
 
-fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
+fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
     const comp = self.base.comp;
     const gpa = comp.gpa;
+    const needed_size = try load_commands.calcLoadCommandsSize(self, false);
+    const buffer = try gpa.alloc(u8, needed_size);
+    defer gpa.free(buffer);
 
-    var bw: Writer = .fixed(try gpa.alloc(u8, try load_commands.calcLoadCommandsSize(self, false)));
-    defer gpa.free(bw.buffer);
+    var stream = std.io.fixedBufferStream(buffer);
+    const writer = stream.writer();
 
     var ncmds: usize = 0;
 
@@ -2830,26 +2831,26 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
         const slice = self.sections.slice();
         var sect_id: usize = 0;
         for (self.segments.items) |seg| {
-            try bw.writeStruct(seg);
+            try writer.writeStruct(seg);
             for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
-                try bw.writeStruct(header);
+                try writer.writeStruct(header);
             }
             sect_id += seg.nsects;
         }
         ncmds += self.segments.items.len;
     }
 
-    try bw.writeStruct(self.dyld_info_cmd);
+    try writer.writeStruct(self.dyld_info_cmd);
     ncmds += 1;
-    try bw.writeStruct(self.function_starts_cmd);
+    try writer.writeStruct(self.function_starts_cmd);
     ncmds += 1;
-    try bw.writeStruct(self.data_in_code_cmd);
+    try writer.writeStruct(self.data_in_code_cmd);
     ncmds += 1;
-    try bw.writeStruct(self.symtab_cmd);
+    try writer.writeStruct(self.symtab_cmd);
     ncmds += 1;
-    try bw.writeStruct(self.dysymtab_cmd);
+    try writer.writeStruct(self.dysymtab_cmd);
     ncmds += 1;
-    try load_commands.writeDylinkerLC(&bw);
+    try load_commands.writeDylinkerLC(writer);
     ncmds += 1;
 
     if (self.getInternalObject()) |obj| {
@@ -2860,7 +2861,7 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
                 0
             else
                 @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));
-            try bw.writeStruct(macho.entry_point_command{
+            try writer.writeStruct(macho.entry_point_command{
                 .entryoff = entryoff,
                 .stacksize = self.base.stack_size,
             });
@@ -2869,35 +2870,35 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
     }
 
     if (self.base.isDynLib()) {
-        try load_commands.writeDylibIdLC(self, &bw);
+        try load_commands.writeDylibIdLC(self, writer);
         ncmds += 1;
     }
 
     for (self.rpath_list) |rpath| {
-        try load_commands.writeRpathLC(&bw, rpath);
+        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(&bw, rpath);
+        try load_commands.writeRpathLC(rpath, writer);
         ncmds += 1;
     }
 
-    try bw.writeStruct(macho.source_version_command{ .version = 0 });
+    try writer.writeStruct(macho.source_version_command{ .version = 0 });
     ncmds += 1;
 
     if (self.platform.isBuildVersionCompatible()) {
-        try load_commands.writeBuildVersionLC(&bw, self.platform, self.sdk_version);
+        try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, writer);
         ncmds += 1;
     } else {
-        try load_commands.writeVersionMinLC(&bw, self.platform, self.sdk_version);
+        try load_commands.writeVersionMinLC(self.platform, self.sdk_version, writer);
         ncmds += 1;
     }
 
-    const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + bw.count;
-    try bw.writeStruct(self.uuid_cmd);
+    const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos;
+    try writer.writeStruct(self.uuid_cmd);
     ncmds += 1;
 
     for (self.dylibs.items) |index| {
@@ -2915,19 +2916,20 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
             .timestamp = dylib_id.timestamp,
             .current_version = dylib_id.current_version,
             .compatibility_version = dylib_id.compatibility_version,
-        }, &bw);
+        }, writer);
         ncmds += 1;
     }
 
     if (self.requiresCodeSig()) {
-        try bw.writeStruct(self.codesig_cmd);
+        try writer.writeStruct(self.codesig_cmd);
         ncmds += 1;
     }
 
-    assert(bw.end == bw.buffer.len);
-    try self.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
+    assert(stream.pos == needed_size);
 
-    return .{ ncmds, bw.end, uuid_cmd_offset };
+    try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
+
+    return .{ ncmds, buffer.len, uuid_cmd_offset };
 }
 
 fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {
@@ -3010,27 +3012,27 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
 }
 
 pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
-    const gpa = self.base.comp.gpa;
     const seg = self.getTextSegment();
     const offset = self.codesig_cmd.dataoff;
 
-    var bw: Writer = .fixed(try gpa.alloc(u8, code_sig.size()));
-    defer gpa.free(bw.buffer);
+    var buffer = std.ArrayList(u8).init(self.base.comp.gpa);
+    defer buffer.deinit();
+    try buffer.ensureTotalCapacityPrecise(code_sig.size());
     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(),
-    }, &bw);
+    }, buffer.writer());
+    assert(buffer.items.len == code_sig.size());
 
     log.debug("writing code signature from 0x{x} to 0x{x}", .{
         offset,
-        offset + bw.end,
+        offset + buffer.items.len,
     });
 
-    assert(bw.end == bw.buffer.len);
-    try self.pwriteAll(bw.buffer, offset);
+    try self.pwriteAll(buffer.items, offset);
 }
 
 pub fn updateFunc(
@@ -3339,7 +3341,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
     }
 
     const appendSect = struct {
-        fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u4) void {
+        fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u8) void {
             const sect = &macho_file.sections.items(.header)[sect_id];
             const seg = macho_file.segments.items[seg_id];
             sect.addr = seg.vmaddr;
@@ -3598,7 +3600,7 @@ inline fn requiresThunks(self: MachO) bool {
 }
 
 pub fn isZigSegment(self: MachO, seg_id: u8) bool {
-    inline for (&[_]?u4{
+    inline for (&[_]?u8{
         self.zig_text_seg_index,
         self.zig_const_seg_index,
         self.zig_data_seg_index,
@@ -3646,9 +3648,9 @@ pub fn addSegment(self: *MachO, name: []const u8, opts: struct {
     fileoff: u64 = 0,
     filesize: u64 = 0,
     prot: macho.vm_prot_t = macho.PROT.NONE,
-}) error{OutOfMemory}!u4 {
+}) error{OutOfMemory}!u8 {
     const gpa = self.base.comp.gpa;
-    const index: u4 = @intCast(self.segments.items.len);
+    const index = @as(u8, @intCast(self.segments.items.len));
     try self.segments.append(gpa, .{
         .segname = makeStaticString(name),
         .vmaddr = opts.vmaddr,
@@ -3698,9 +3700,9 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 {
     return buf;
 }
 
-pub fn getSegmentByName(self: MachO, segname: []const u8) ?u4 {
+pub fn getSegmentByName(self: MachO, segname: []const u8) ?u8 {
     for (self.segments.items, 0..) |seg, i| {
-        if (mem.eql(u8, segname, seg.segName())) return @intCast(i);
+        if (mem.eql(u8, segname, seg.segName())) return @as(u8, @intCast(i));
     } else return null;
 }
 
@@ -4028,7 +4030,7 @@ const default_entry_symbol_name = "_main";
 
 const Section = struct {
     header: macho.section_64,
-    segment_id: u4,
+    segment_id: u8,
     atoms: std.ArrayListUnmanaged(Ref) = .empty,
     free_list: std.ArrayListUnmanaged(Atom.Index) = .empty,
     last_atom_index: Atom.Index = 0,
@@ -4353,7 +4355,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
 // The file/property is also available with vendored libc.
 fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {
     const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" });
-    const contents = try fs.cwd().readFileAlloc(sdk_path, arena, .limited(std.math.maxInt(u16)));
+    const contents = try fs.cwd().readFileAlloc(arena, sdk_path, std.math.maxInt(u16));
     const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});
     if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;
     return error.SdkVersionFailure;
@@ -4369,7 +4371,7 @@ fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion {
     };
 
     const parseNext = struct {
-        fn parseNext(it: *std.mem.SplitIterator(u8, .any)) ?u16 {
+        fn parseNext(it: anytype) ?u16 {
             const nn = it.next() orelse return null;
             return std.fmt.parseInt(u16, nn, 10) catch null;
         }
@@ -5317,11 +5319,8 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
 pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void {
     const comp = macho_file.base.comp;
     const diags = &comp.link_diags;
-    var fw = macho_file.base.file.?.writer();
-    fw.pos = offset;
-    var bw = fw.interface().unbuffered();
-    bw.writeAll(bytes) catch |err| switch (err) {
-        error.WriteFailed => return diags.fail("failed to write: {s}", .{@errorName(fw.err.?)}),
+    macho_file.base.file.?.pwriteAll(bytes, offset) catch |err| {
+        return diags.fail("failed to write: {s}", .{@errorName(err)});
     };
 }