authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 18:40:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-07 22:43:52-07:00
log49be02e6d75acd996d9b2a573714552ba081ea13
tree171efca8e110fda0bbbedea433367a7d0e526761
parentc8fcd2ff2c032b2de8cc1a57e075552d1cab35df

MachO: revert unfinished changes


21 files changed, 818 insertions(+), 625 deletions(-)

src/link/MachO.zig+100-101
...@@ -41,9 +41,9 @@ data_in_code_cmd: macho.linkedit_data_command = .{ .cmd = .DATA_IN_CODE },...@@ -41,9 +41,9 @@ data_in_code_cmd: macho.linkedit_data_command = .{ .cmd = .DATA_IN_CODE },
41uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },41uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },
42codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },42codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },
4343
44pagezero_seg_index: ?u4 = null,44pagezero_seg_index: ?u8 = null,
45text_seg_index: ?u4 = null,45text_seg_index: ?u8 = null,
46linkedit_seg_index: ?u4 = null,46linkedit_seg_index: ?u8 = null,
47text_sect_index: ?u8 = null,47text_sect_index: ?u8 = null,
48data_sect_index: ?u8 = null,48data_sect_index: ?u8 = null,
49got_sect_index: ?u8 = null,49got_sect_index: ?u8 = null,
...@@ -76,10 +76,10 @@ unwind_info: UnwindInfo = .{},...@@ -76,10 +76,10 @@ unwind_info: UnwindInfo = .{},
76data_in_code: DataInCode = .{},76data_in_code: DataInCode = .{},
7777
78/// Tracked loadable segments during incremental linking.78/// Tracked loadable segments during incremental linking.
79zig_text_seg_index: ?u4 = null,79zig_text_seg_index: ?u8 = null,
80zig_const_seg_index: ?u4 = null,80zig_const_seg_index: ?u8 = null,
81zig_data_seg_index: ?u4 = null,81zig_data_seg_index: ?u8 = null,
82zig_bss_seg_index: ?u4 = null,82zig_bss_seg_index: ?u8 = null,
8383
84/// Tracked section headers with incremental updates to Zig object.84/// Tracked section headers with incremental updates to Zig object.
85zig_text_sect_index: ?u8 = null,85zig_text_sect_index: ?u8 = null,
...@@ -591,7 +591,6 @@ pub fn flush(...@@ -591,7 +591,6 @@ pub fn flush(
591 error.NoSpaceLeft => unreachable,591 error.NoSpaceLeft => unreachable,
592 error.OutOfMemory => return error.OutOfMemory,592 error.OutOfMemory => return error.OutOfMemory,
593 error.LinkFailure => return error.LinkFailure,593 error.LinkFailure => return error.LinkFailure,
594 else => unreachable,
595 };594 };
596 try self.writeHeader(ncmds, sizeofcmds);595 try self.writeHeader(ncmds, sizeofcmds);
597 self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) {596 self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) {
...@@ -1075,7 +1074,7 @@ fn accessLibPath(...@@ -1075,7 +1074,7 @@ fn accessLibPath(
10751074
1076 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1075 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1077 test_path.clearRetainingCapacity();1076 test_path.clearRetainingCapacity();
1078 try test_path.print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });1077 try test_path.writer().print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
1079 try checked_paths.append(try arena.dupe(u8, test_path.items));1078 try checked_paths.append(try arena.dupe(u8, test_path.items));
1080 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {1079 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
1081 error.FileNotFound => continue,1080 error.FileNotFound => continue,
...@@ -1098,7 +1097,7 @@ fn accessFrameworkPath(...@@ -1098,7 +1097,7 @@ fn accessFrameworkPath(
10981097
1099 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1098 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1100 test_path.clearRetainingCapacity();1099 test_path.clearRetainingCapacity();
1101 try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{1100 try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
1102 search_dir,1101 search_dir,
1103 name,1102 name,
1104 name,1103 name,
...@@ -1179,9 +1178,9 @@ fn parseDependentDylibs(self: *MachO) !void {...@@ -1179,9 +1178,9 @@ fn parseDependentDylibs(self: *MachO) !void {
1179 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1178 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1180 test_path.clearRetainingCapacity();1179 test_path.clearRetainingCapacity();
1181 if (self.base.comp.sysroot) |root| {1180 if (self.base.comp.sysroot) |root| {
1182 try test_path.print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });1181 try test_path.writer().print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
1183 } else {1182 } else {
1184 try test_path.print("{s}{s}", .{ path, ext });1183 try test_path.writer().print("{s}{s}", .{ path, ext });
1185 }1184 }
1186 try checked_paths.append(try arena.dupe(u8, test_path.items));1185 try checked_paths.append(try arena.dupe(u8, test_path.items));
1187 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {1186 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
...@@ -2132,7 +2131,7 @@ fn initSegments(self: *MachO) !void {...@@ -2132,7 +2131,7 @@ fn initSegments(self: *MachO) !void {
21322131
2133 mem.sort(Entry, entries.items, self, Entry.lessThan);2132 mem.sort(Entry, entries.items, self, Entry.lessThan);
21342133
2135 const backlinks = try gpa.alloc(u4, entries.items.len);2134 const backlinks = try gpa.alloc(u8, entries.items.len);
2136 defer gpa.free(backlinks);2135 defer gpa.free(backlinks);
2137 for (entries.items, 0..) |entry, i| {2136 for (entries.items, 0..) |entry, i| {
2138 backlinks[entry.index] = @intCast(i);2137 backlinks[entry.index] = @intCast(i);
...@@ -2146,7 +2145,7 @@ fn initSegments(self: *MachO) !void {...@@ -2146,7 +2145,7 @@ fn initSegments(self: *MachO) !void {
2146 self.segments.appendAssumeCapacity(segments[sorted.index]);2145 self.segments.appendAssumeCapacity(segments[sorted.index]);
2147 }2146 }
21482147
2149 for (&[_]*?u4{2148 for (&[_]*?u8{
2150 &self.pagezero_seg_index,2149 &self.pagezero_seg_index,
2151 &self.text_seg_index,2150 &self.text_seg_index,
2152 &self.linkedit_seg_index,2151 &self.linkedit_seg_index,
...@@ -2164,7 +2163,7 @@ fn initSegments(self: *MachO) !void {...@@ -2164,7 +2163,7 @@ fn initSegments(self: *MachO) !void {
2164 for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| {2163 for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| {
2165 const segname = header.segName();2164 const segname = header.segName();
2166 const segment_id = self.getSegmentByName(segname) orelse blk: {2165 const segment_id = self.getSegmentByName(segname) orelse blk: {
2167 const segment_id: u4 = @intCast(self.segments.items.len);2166 const segment_id = @as(u8, @intCast(self.segments.items.len));
2168 const protection = getSegmentProt(segname);2167 const protection = getSegmentProt(segname);
2169 try self.segments.append(gpa, .{2168 try self.segments.append(gpa, .{
2170 .cmdsize = @sizeOf(macho.segment_command_64),2169 .cmdsize = @sizeOf(macho.segment_command_64),
...@@ -2527,8 +2526,10 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {...@@ -2527,8 +2526,10 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
25272526
2528 const doWork = struct {2527 const doWork = struct {
2529 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {2528 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
2530 var bw: Writer = .fixed(buffer[try macho_file.cast(usize, th.value)..][0..th.size()]);2529 const off = try macho_file.cast(usize, th.value);
2531 try th.write(macho_file, &bw);2530 const size = th.size();
2531 var stream = std.io.fixedBufferStream(buffer[off..][0..size]);
2532 try th.write(macho_file, stream.writer());
2532 }2533 }
2533 }.doWork;2534 }.doWork;
2534 const out = self.sections.items(.out)[thunk.out_n_sect].items;2535 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 {...@@ -2555,15 +2556,15 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {
25552556
2556 const doWork = struct {2557 const doWork = struct {
2557 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {2558 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {
2558 var bw: Writer = .fixed(buffer);2559 var stream = std.io.fixedBufferStream(buffer);
2559 switch (tag) {2560 switch (tag) {
2560 .eh_frame => eh_frame.write(macho_file, buffer),2561 .eh_frame => eh_frame.write(macho_file, buffer),
2561 .unwind_info => try macho_file.unwind_info.write(macho_file, &bw),2562 .unwind_info => try macho_file.unwind_info.write(macho_file, buffer),
2562 .got => try macho_file.got.write(macho_file, &bw),2563 .got => try macho_file.got.write(macho_file, stream.writer()),
2563 .stubs => try macho_file.stubs.write(macho_file, &bw),2564 .stubs => try macho_file.stubs.write(macho_file, stream.writer()),
2564 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, &bw),2565 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, stream.writer()),
2565 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, &bw),2566 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, stream.writer()),
2566 .objc_stubs => try macho_file.objc_stubs.write(macho_file, &bw),2567 .objc_stubs => try macho_file.objc_stubs.write(macho_file, stream.writer()),
2567 }2568 }
2568 }2569 }
2569 }.doWork;2570 }.doWork;
...@@ -2604,8 +2605,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {...@@ -2604,8 +2605,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {
2604 try macho_file.lazy_bind_section.updateSize(macho_file);2605 try macho_file.lazy_bind_section.updateSize(macho_file);
2605 const sect_id = macho_file.stubs_helper_sect_index.?;2606 const sect_id = macho_file.stubs_helper_sect_index.?;
2606 const out = &macho_file.sections.items(.out)[sect_id];2607 const out = &macho_file.sections.items(.out)[sect_id];
2607 var bw: Writer = .fixed(out.items);2608 var stream = std.io.fixedBufferStream(out.items);
2608 try macho_file.stubs_helper.write(macho_file, &bw);2609 try macho_file.stubs_helper.write(macho_file, stream.writer());
2609 }2610 }
2610 }.doWork;2611 }.doWork;
2611 doWork(self) catch |err|2612 doWork(self) catch |err|
...@@ -2664,49 +2665,46 @@ fn writeDyldInfo(self: *MachO) !void {...@@ -2664,49 +2665,46 @@ fn writeDyldInfo(self: *MachO) !void {
2664 needed_size += cmd.lazy_bind_size;2665 needed_size += cmd.lazy_bind_size;
2665 needed_size += cmd.export_size;2666 needed_size += cmd.export_size;
26662667
2667 var bw: Writer = .fixed(try gpa.alloc(u8, needed_size));2668 const buffer = try gpa.alloc(u8, needed_size);
2668 defer gpa.free(bw.buffer);2669 defer gpa.free(buffer);
2669 @memset(bw.buffer, 0);2670 @memset(buffer, 0);
26702671
2671 try self.rebase_section.write(&bw);2672 var stream = std.io.fixedBufferStream(buffer);
2672 bw.end = cmd.bind_off - base_off;2673 const writer = stream.writer();
2673 try self.bind_section.write(&bw);2674
2674 bw.end = cmd.weak_bind_off - base_off;2675 try self.rebase_section.write(writer);
2675 try self.weak_bind_section.write(&bw);2676 try stream.seekTo(cmd.bind_off - base_off);
2676 bw.end = cmd.lazy_bind_off - base_off;2677 try self.bind_section.write(writer);
2677 try self.lazy_bind_section.write(&bw);2678 try stream.seekTo(cmd.weak_bind_off - base_off);
2678 bw.end = cmd.export_off - base_off;2679 try self.weak_bind_section.write(writer);
2679 try self.export_trie.write(&bw);2680 try stream.seekTo(cmd.lazy_bind_off - base_off);
2680 try self.pwriteAll(bw.buffer, cmd.rebase_off);2681 try self.lazy_bind_section.write(writer);
2682 try stream.seekTo(cmd.export_off - base_off);
2683 try self.export_trie.write(writer);
2684 try self.pwriteAll(buffer, cmd.rebase_off);
2681}2685}
26822686
2683pub fn writeDataInCode(self: *MachO) link.File.FlushError!void {2687pub fn writeDataInCode(self: *MachO) !void {
2684 const tracy = trace(@src());2688 const tracy = trace(@src());
2685 defer tracy.end();2689 defer tracy.end();
2686 const gpa = self.base.comp.gpa;2690 const gpa = self.base.comp.gpa;
2687 const cmd = self.data_in_code_cmd;2691 const cmd = self.data_in_code_cmd;
26882692 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size());
2689 var bw: Writer = .fixed(try gpa.alloc(u8, self.data_in_code.size()));2693 defer buffer.deinit();
2690 defer gpa.free(bw.buffer);2694 try self.data_in_code.write(self, buffer.writer());
26912695 try self.pwriteAll(buffer.items, cmd.dataoff);
2692 try self.data_in_code.write(self, &bw);
2693 assert(bw.end == bw.buffer.len);
2694 try self.pwriteAll(bw.buffer, cmd.dataoff);
2695}2696}
26962697
2697fn writeIndsymtab(self: *MachO) !void {2698fn writeIndsymtab(self: *MachO) !void {
2698 const tracy = trace(@src());2699 const tracy = trace(@src());
2699 defer tracy.end();2700 defer tracy.end();
2700
2701 const gpa = self.base.comp.gpa;2701 const gpa = self.base.comp.gpa;
2702 const cmd = self.dysymtab_cmd;2702 const cmd = self.dysymtab_cmd;
27032703 const needed_size = cmd.nindirectsyms * @sizeOf(u32);
2704 var bw: Writer = .fixed(try gpa.alloc(u8, @sizeOf(u32) * cmd.nindirectsyms));2704 var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size);
2705 defer gpa.free(bw.buffer);2705 defer buffer.deinit();
27062706 try self.indsymtab.write(self, buffer.writer());
2707 try self.indsymtab.write(self, &bw);2707 try self.pwriteAll(buffer.items, cmd.indirectsymoff);
2708 assert(bw.end == bw.buffer.len);
2709 try self.pwriteAll(bw.buffer, cmd.indirectsymoff);
2710}2708}
27112709
2712pub fn writeSymtabToFile(self: *MachO) !void {2710pub fn writeSymtabToFile(self: *MachO) !void {
...@@ -2816,12 +2814,15 @@ fn calcSymtabSize(self: *MachO) !void {...@@ -2816,12 +2814,15 @@ fn calcSymtabSize(self: *MachO) !void {
2816 }2814 }
2817}2815}
28182816
2819fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {2817fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2820 const comp = self.base.comp;2818 const comp = self.base.comp;
2821 const gpa = comp.gpa;2819 const gpa = comp.gpa;
2820 const needed_size = try load_commands.calcLoadCommandsSize(self, false);
2821 const buffer = try gpa.alloc(u8, needed_size);
2822 defer gpa.free(buffer);
28222823
2823 var bw: Writer = .fixed(try gpa.alloc(u8, try load_commands.calcLoadCommandsSize(self, false)));2824 var stream = std.io.fixedBufferStream(buffer);
2824 defer gpa.free(bw.buffer);2825 const writer = stream.writer();
28252826
2826 var ncmds: usize = 0;2827 var ncmds: usize = 0;
28272828
...@@ -2830,26 +2831,26 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {...@@ -2830,26 +2831,26 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
2830 const slice = self.sections.slice();2831 const slice = self.sections.slice();
2831 var sect_id: usize = 0;2832 var sect_id: usize = 0;
2832 for (self.segments.items) |seg| {2833 for (self.segments.items) |seg| {
2833 try bw.writeStruct(seg);2834 try writer.writeStruct(seg);
2834 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {2835 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
2835 try bw.writeStruct(header);2836 try writer.writeStruct(header);
2836 }2837 }
2837 sect_id += seg.nsects;2838 sect_id += seg.nsects;
2838 }2839 }
2839 ncmds += self.segments.items.len;2840 ncmds += self.segments.items.len;
2840 }2841 }
28412842
2842 try bw.writeStruct(self.dyld_info_cmd);2843 try writer.writeStruct(self.dyld_info_cmd);
2843 ncmds += 1;2844 ncmds += 1;
2844 try bw.writeStruct(self.function_starts_cmd);2845 try writer.writeStruct(self.function_starts_cmd);
2845 ncmds += 1;2846 ncmds += 1;
2846 try bw.writeStruct(self.data_in_code_cmd);2847 try writer.writeStruct(self.data_in_code_cmd);
2847 ncmds += 1;2848 ncmds += 1;
2848 try bw.writeStruct(self.symtab_cmd);2849 try writer.writeStruct(self.symtab_cmd);
2849 ncmds += 1;2850 ncmds += 1;
2850 try bw.writeStruct(self.dysymtab_cmd);2851 try writer.writeStruct(self.dysymtab_cmd);
2851 ncmds += 1;2852 ncmds += 1;
2852 try load_commands.writeDylinkerLC(&bw);2853 try load_commands.writeDylinkerLC(writer);
2853 ncmds += 1;2854 ncmds += 1;
28542855
2855 if (self.getInternalObject()) |obj| {2856 if (self.getInternalObject()) |obj| {
...@@ -2860,7 +2861,7 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {...@@ -2860,7 +2861,7 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
2860 02861 0
2861 else2862 else
2862 @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));2863 @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));
2863 try bw.writeStruct(macho.entry_point_command{2864 try writer.writeStruct(macho.entry_point_command{
2864 .entryoff = entryoff,2865 .entryoff = entryoff,
2865 .stacksize = self.base.stack_size,2866 .stacksize = self.base.stack_size,
2866 });2867 });
...@@ -2869,35 +2870,35 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {...@@ -2869,35 +2870,35 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
2869 }2870 }
28702871
2871 if (self.base.isDynLib()) {2872 if (self.base.isDynLib()) {
2872 try load_commands.writeDylibIdLC(self, &bw);2873 try load_commands.writeDylibIdLC(self, writer);
2873 ncmds += 1;2874 ncmds += 1;
2874 }2875 }
28752876
2876 for (self.rpath_list) |rpath| {2877 for (self.rpath_list) |rpath| {
2877 try load_commands.writeRpathLC(&bw, rpath);2878 try load_commands.writeRpathLC(rpath, writer);
2878 ncmds += 1;2879 ncmds += 1;
2879 }2880 }
2880 if (comp.config.any_sanitize_thread) {2881 if (comp.config.any_sanitize_thread) {
2881 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);2882 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
2882 defer gpa.free(path);2883 defer gpa.free(path);
2883 const rpath = std.fs.path.dirname(path) orelse ".";2884 const rpath = std.fs.path.dirname(path) orelse ".";
2884 try load_commands.writeRpathLC(&bw, rpath);2885 try load_commands.writeRpathLC(rpath, writer);
2885 ncmds += 1;2886 ncmds += 1;
2886 }2887 }
28872888
2888 try bw.writeStruct(macho.source_version_command{ .version = 0 });2889 try writer.writeStruct(macho.source_version_command{ .version = 0 });
2889 ncmds += 1;2890 ncmds += 1;
28902891
2891 if (self.platform.isBuildVersionCompatible()) {2892 if (self.platform.isBuildVersionCompatible()) {
2892 try load_commands.writeBuildVersionLC(&bw, self.platform, self.sdk_version);2893 try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, writer);
2893 ncmds += 1;2894 ncmds += 1;
2894 } else {2895 } else {
2895 try load_commands.writeVersionMinLC(&bw, self.platform, self.sdk_version);2896 try load_commands.writeVersionMinLC(self.platform, self.sdk_version, writer);
2896 ncmds += 1;2897 ncmds += 1;
2897 }2898 }
28982899
2899 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + bw.count;2900 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos;
2900 try bw.writeStruct(self.uuid_cmd);2901 try writer.writeStruct(self.uuid_cmd);
2901 ncmds += 1;2902 ncmds += 1;
29022903
2903 for (self.dylibs.items) |index| {2904 for (self.dylibs.items) |index| {
...@@ -2915,19 +2916,20 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {...@@ -2915,19 +2916,20 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
2915 .timestamp = dylib_id.timestamp,2916 .timestamp = dylib_id.timestamp,
2916 .current_version = dylib_id.current_version,2917 .current_version = dylib_id.current_version,
2917 .compatibility_version = dylib_id.compatibility_version,2918 .compatibility_version = dylib_id.compatibility_version,
2918 }, &bw);2919 }, writer);
2919 ncmds += 1;2920 ncmds += 1;
2920 }2921 }
29212922
2922 if (self.requiresCodeSig()) {2923 if (self.requiresCodeSig()) {
2923 try bw.writeStruct(self.codesig_cmd);2924 try writer.writeStruct(self.codesig_cmd);
2924 ncmds += 1;2925 ncmds += 1;
2925 }2926 }
29262927
2927 assert(bw.end == bw.buffer.len);2928 assert(stream.pos == needed_size);
2928 try self.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
29292929
2930 return .{ ncmds, bw.end, uuid_cmd_offset };2930 try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
2931
2932 return .{ ncmds, buffer.len, uuid_cmd_offset };
2931}2933}
29322934
2933fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {2935fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {
...@@ -3010,27 +3012,27 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {...@@ -3010,27 +3012,27 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
3010}3012}
30113013
3012pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {3014pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
3013 const gpa = self.base.comp.gpa;
3014 const seg = self.getTextSegment();3015 const seg = self.getTextSegment();
3015 const offset = self.codesig_cmd.dataoff;3016 const offset = self.codesig_cmd.dataoff;
30163017
3017 var bw: Writer = .fixed(try gpa.alloc(u8, code_sig.size()));3018 var buffer = std.ArrayList(u8).init(self.base.comp.gpa);
3018 defer gpa.free(bw.buffer);3019 defer buffer.deinit();
3020 try buffer.ensureTotalCapacityPrecise(code_sig.size());
3019 try code_sig.writeAdhocSignature(self, .{3021 try code_sig.writeAdhocSignature(self, .{
3020 .file = self.base.file.?,3022 .file = self.base.file.?,
3021 .exec_seg_base = seg.fileoff,3023 .exec_seg_base = seg.fileoff,
3022 .exec_seg_limit = seg.filesize,3024 .exec_seg_limit = seg.filesize,
3023 .file_size = offset,3025 .file_size = offset,
3024 .dylib = self.base.isDynLib(),3026 .dylib = self.base.isDynLib(),
3025 }, &bw);3027 }, buffer.writer());
3028 assert(buffer.items.len == code_sig.size());
30263029
3027 log.debug("writing code signature from 0x{x} to 0x{x}", .{3030 log.debug("writing code signature from 0x{x} to 0x{x}", .{
3028 offset,3031 offset,
3029 offset + bw.end,3032 offset + buffer.items.len,
3030 });3033 });
30313034
3032 assert(bw.end == bw.buffer.len);3035 try self.pwriteAll(buffer.items, offset);
3033 try self.pwriteAll(bw.buffer, offset);
3034}3036}
30353037
3036pub fn updateFunc(3038pub fn updateFunc(
...@@ -3339,7 +3341,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3339,7 +3341,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3339 }3341 }
33403342
3341 const appendSect = struct {3343 const appendSect = struct {
3342 fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u4) void {3344 fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u8) void {
3343 const sect = &macho_file.sections.items(.header)[sect_id];3345 const sect = &macho_file.sections.items(.header)[sect_id];
3344 const seg = macho_file.segments.items[seg_id];3346 const seg = macho_file.segments.items[seg_id];
3345 sect.addr = seg.vmaddr;3347 sect.addr = seg.vmaddr;
...@@ -3598,7 +3600,7 @@ inline fn requiresThunks(self: MachO) bool {...@@ -3598,7 +3600,7 @@ inline fn requiresThunks(self: MachO) bool {
3598}3600}
35993601
3600pub fn isZigSegment(self: MachO, seg_id: u8) bool {3602pub fn isZigSegment(self: MachO, seg_id: u8) bool {
3601 inline for (&[_]?u4{3603 inline for (&[_]?u8{
3602 self.zig_text_seg_index,3604 self.zig_text_seg_index,
3603 self.zig_const_seg_index,3605 self.zig_const_seg_index,
3604 self.zig_data_seg_index,3606 self.zig_data_seg_index,
...@@ -3646,9 +3648,9 @@ pub fn addSegment(self: *MachO, name: []const u8, opts: struct {...@@ -3646,9 +3648,9 @@ pub fn addSegment(self: *MachO, name: []const u8, opts: struct {
3646 fileoff: u64 = 0,3648 fileoff: u64 = 0,
3647 filesize: u64 = 0,3649 filesize: u64 = 0,
3648 prot: macho.vm_prot_t = macho.PROT.NONE,3650 prot: macho.vm_prot_t = macho.PROT.NONE,
3649}) error{OutOfMemory}!u4 {3651}) error{OutOfMemory}!u8 {
3650 const gpa = self.base.comp.gpa;3652 const gpa = self.base.comp.gpa;
3651 const index: u4 = @intCast(self.segments.items.len);3653 const index = @as(u8, @intCast(self.segments.items.len));
3652 try self.segments.append(gpa, .{3654 try self.segments.append(gpa, .{
3653 .segname = makeStaticString(name),3655 .segname = makeStaticString(name),
3654 .vmaddr = opts.vmaddr,3656 .vmaddr = opts.vmaddr,
...@@ -3698,9 +3700,9 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 {...@@ -3698,9 +3700,9 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 {
3698 return buf;3700 return buf;
3699}3701}
37003702
3701pub fn getSegmentByName(self: MachO, segname: []const u8) ?u4 {3703pub fn getSegmentByName(self: MachO, segname: []const u8) ?u8 {
3702 for (self.segments.items, 0..) |seg, i| {3704 for (self.segments.items, 0..) |seg, i| {
3703 if (mem.eql(u8, segname, seg.segName())) return @intCast(i);3705 if (mem.eql(u8, segname, seg.segName())) return @as(u8, @intCast(i));
3704 } else return null;3706 } else return null;
3705}3707}
37063708
...@@ -4028,7 +4030,7 @@ const default_entry_symbol_name = "_main";...@@ -4028,7 +4030,7 @@ const default_entry_symbol_name = "_main";
40284030
4029const Section = struct {4031const Section = struct {
4030 header: macho.section_64,4032 header: macho.section_64,
4031 segment_id: u4,4033 segment_id: u8,
4032 atoms: std.ArrayListUnmanaged(Ref) = .empty,4034 atoms: std.ArrayListUnmanaged(Ref) = .empty,
4033 free_list: std.ArrayListUnmanaged(Atom.Index) = .empty,4035 free_list: std.ArrayListUnmanaged(Atom.Index) = .empty,
4034 last_atom_index: Atom.Index = 0,4036 last_atom_index: Atom.Index = 0,
...@@ -4353,7 +4355,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi...@@ -4353,7 +4355,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
4353// The file/property is also available with vendored libc.4355// The file/property is also available with vendored libc.
4354fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {4356fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {
4355 const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" });4357 const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" });
4356 const contents = try fs.cwd().readFileAlloc(sdk_path, arena, .limited(std.math.maxInt(u16)));4358 const contents = try fs.cwd().readFileAlloc(arena, sdk_path, std.math.maxInt(u16));
4357 const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});4359 const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});
4358 if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;4360 if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;
4359 return error.SdkVersionFailure;4361 return error.SdkVersionFailure;
...@@ -4369,7 +4371,7 @@ fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion {...@@ -4369,7 +4371,7 @@ fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion {
4369 };4371 };
43704372
4371 const parseNext = struct {4373 const parseNext = struct {
4372 fn parseNext(it: *std.mem.SplitIterator(u8, .any)) ?u16 {4374 fn parseNext(it: anytype) ?u16 {
4373 const nn = it.next() orelse return null;4375 const nn = it.next() orelse return null;
4374 return std.fmt.parseInt(u16, nn, 10) catch null;4376 return std.fmt.parseInt(u16, nn, 10) catch null;
4375 }4377 }
...@@ -5317,11 +5319,8 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {...@@ -5317,11 +5319,8 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
5317pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void {5319pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void {
5318 const comp = macho_file.base.comp;5320 const comp = macho_file.base.comp;
5319 const diags = &comp.link_diags;5321 const diags = &comp.link_diags;
5320 var fw = macho_file.base.file.?.writer();5322 macho_file.base.file.?.pwriteAll(bytes, offset) catch |err| {
5321 fw.pos = offset;5323 return diags.fail("failed to write: {s}", .{@errorName(err)});
5322 var bw = fw.interface().unbuffered();
5323 bw.writeAll(bytes) catch |err| switch (err) {
5324 error.WriteFailed => return diags.fail("failed to write: {s}", .{@errorName(fw.err.?)}),
5325 };5324 };
5326}5325}
53275326
src/link/MachO/Archive.zig+49-22
...@@ -71,29 +71,53 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File...@@ -71,29 +71,53 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
71 .mtime = hdr.date() catch 0,71 .mtime = hdr.date() catch 0,
72 };72 };
7373
74 log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path });74 log.debug("extracting object '{}' from archive '{}'", .{ object.path, path });
7575
76 try self.objects.append(gpa, object);76 try self.objects.append(gpa, object);
77 }77 }
78}78}
7979
80pub fn writeHeader(80pub fn writeHeader(
81 bw: *Writer,
82 object_name: []const u8,81 object_name: []const u8,
83 object_size: usize,82 object_size: usize,
84 format: Format,83 format: Format,
85) Writer.Error!void {84 writer: anytype,
86 var hdr: ar_hdr = undefined;85) !void {
87 @memset(mem.asBytes(&hdr), ' ');86 var hdr: ar_hdr = .{
88 inline for (@typeInfo(ar_hdr).@"struct".fields) |field| @field(hdr, field.name)[0] = '0';87 .ar_name = undefined,
88 .ar_date = undefined,
89 .ar_uid = undefined,
90 .ar_gid = undefined,
91 .ar_mode = undefined,
92 .ar_size = undefined,
93 .ar_fmag = undefined,
94 };
95 @memset(mem.asBytes(&hdr), 0x20);
96 inline for (@typeInfo(ar_hdr).@"struct".fields) |field| {
97 var stream = std.io.fixedBufferStream(&@field(hdr, field.name));
98 stream.writer().print("0", .{}) catch unreachable;
99 }
89 @memcpy(&hdr.ar_fmag, ARFMAG);100 @memcpy(&hdr.ar_fmag, ARFMAG);
101
90 const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format));102 const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format));
91 _ = std.fmt.bufPrint(&hdr.ar_name, "#1/{d}", .{object_name_len}) catch unreachable;
92 const total_object_size = object_size + object_name_len;103 const total_object_size = object_size + object_name_len;
93 _ = std.fmt.bufPrint(&hdr.ar_size, "{d}", .{total_object_size}) catch unreachable;104
94 try bw.writeStruct(hdr);105 {
95 try bw.writeAll(object_name);106 var stream = std.io.fixedBufferStream(&hdr.ar_name);
96 try bw.splatByteAll(0, object_name_len - object_name.len);107 stream.writer().print("#1/{d}", .{object_name_len}) catch unreachable;
108 }
109 {
110 var stream = std.io.fixedBufferStream(&hdr.ar_size);
111 stream.writer().print("{d}", .{total_object_size}) catch unreachable;
112 }
113
114 try writer.writeAll(mem.asBytes(&hdr));
115 try writer.print("{s}\x00", .{object_name});
116
117 const padding = object_name_len - object_name.len - 1;
118 if (padding > 0) {
119 try writer.writeByteNTimes(0, padding);
120 }
97}121}
98122
99// Archive files start with the ARMAG identifying string. Then follows a123// Archive files start with the ARMAG identifying string. Then follows a
...@@ -177,12 +201,12 @@ pub const ArSymtab = struct {...@@ -177,12 +201,12 @@ pub const ArSymtab = struct {
177 return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);201 return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
178 }202 }
179203
180 pub fn write(ar: ArSymtab, bw: *Writer, format: Format, macho_file: *MachO) Writer.Error!void {204 pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: anytype) !void {
181 const ptr_width = ptrWidth(format);205 const ptr_width = ptrWidth(format);
182 // Header206 // Header
183 try writeHeader(bw, SYMDEF, ar.size(format), format);207 try writeHeader(SYMDEF, ar.size(format), format, writer);
184 // Symtab size208 // Symtab size
185 try writeInt(bw, format, ar.entries.items.len * 2 * ptr_width);209 try writeInt(format, ar.entries.items.len * 2 * ptr_width, writer);
186 // Symtab entries210 // Symtab entries
187 for (ar.entries.items) |entry| {211 for (ar.entries.items) |entry| {
188 const file_off = switch (macho_file.getFile(entry.file).?) {212 const file_off = switch (macho_file.getFile(entry.file).?) {
...@@ -191,16 +215,19 @@ pub const ArSymtab = struct {...@@ -191,16 +215,19 @@ pub const ArSymtab = struct {
191 else => unreachable,215 else => unreachable,
192 };216 };
193 // Name offset217 // Name offset
194 try writeInt(bw, format, entry.off);218 try writeInt(format, entry.off, writer);
195 // File offset219 // File offset
196 try writeInt(bw, format, file_off);220 try writeInt(format, file_off, writer);
197 }221 }
198 // Strtab size222 // Strtab size
199 const strtab_size = mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);223 const strtab_size = mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
200 try writeInt(bw, format, strtab_size);224 const padding = strtab_size - ar.strtab.buffer.items.len;
225 try writeInt(format, strtab_size, writer);
201 // Strtab226 // Strtab
202 try bw.writeAll(ar.strtab.buffer.items);227 try writer.writeAll(ar.strtab.buffer.items);
203 try bw.splatByteAll(0, strtab_size - ar.strtab.buffer.items.len);228 if (padding > 0) {
229 try writer.writeByteNTimes(0, padding);
230 }
204 }231 }
205232
206 const PrintFormat = struct {233 const PrintFormat = struct {
...@@ -248,10 +275,10 @@ pub fn ptrWidth(format: Format) usize {...@@ -248,10 +275,10 @@ pub fn ptrWidth(format: Format) usize {
248 };275 };
249}276}
250277
251pub fn writeInt(bw: *Writer, format: Format, value: u64) Writer.Error!void {278pub fn writeInt(format: Format, value: u64, writer: anytype) !void {
252 switch (format) {279 switch (format) {
253 .p32 => try bw.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),280 .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
254 .p64 => try bw.writeInt(u64, value, .little),281 .p64 => try writer.writeInt(u64, value, .little),
255 }282 }
256}283}
257284
src/link/MachO/Atom.zig+45-41
...@@ -580,9 +580,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {...@@ -580,9 +580,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
580580
581 relocs_log.debug("{x}: {s}", .{ self.value, name });581 relocs_log.debug("{x}: {s}", .{ self.value, name });
582582
583 var bw: Writer = .fixed(buffer);
584
585 var has_error = false;583 var has_error = false;
584 var stream = std.io.fixedBufferStream(buffer);
586 var i: usize = 0;585 var i: usize = 0;
587 while (i < relocs.len) : (i += 1) {586 while (i < relocs.len) : (i += 1) {
588 const rel = relocs[i];587 const rel = relocs[i];
...@@ -593,28 +592,30 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {...@@ -593,28 +592,30 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
593 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;592 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;
594 }593 }
595594
596 bw.end = std.math.cast(usize, rel_offset) orelse return error.Overflow;595 try stream.seekTo(rel_offset);
597 self.resolveRelocInner(rel, subtractor, buffer, macho_file, &bw) catch |err| switch (err) {596 self.resolveRelocInner(rel, subtractor, buffer, macho_file, stream.writer()) catch |err| {
598 error.RelaxFail => {597 switch (err) {
599 const target = switch (rel.tag) {598 error.RelaxFail => {
600 .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),599 const target = switch (rel.tag) {
601 .local => rel.getTargetAtom(self, macho_file).getName(macho_file),600 .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),
602 };601 .local => rel.getTargetAtom(self, macho_file).getName(macho_file),
603 try macho_file.reportParseError2(602 };
604 file.getIndex(),603 try macho_file.reportParseError2(
605 "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {f}, target {s}",604 file.getIndex(),
606 .{605 "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {}, target {s}",
607 name,606 .{
608 self.getAddress(macho_file),607 name,
609 rel.offset,608 self.getAddress(macho_file),
610 rel.fmtPretty(macho_file.getTarget().cpu.arch),609 rel.offset,
611 target,610 rel.fmtPretty(macho_file.getTarget().cpu.arch),
612 },611 target,
613 );612 },
614 has_error = true;613 );
615 },614 has_error = true;
616 error.RelaxFailUnexpectedInstruction => has_error = true,615 },
617 else => |e| return e,616 error.RelaxFailUnexpectedInstruction => has_error = true,
617 else => |e| return e,
618 }
618 };619 };
619 }620 }
620621
...@@ -637,8 +638,8 @@ fn resolveRelocInner(...@@ -637,8 +638,8 @@ fn resolveRelocInner(
637 subtractor: ?Relocation,638 subtractor: ?Relocation,
638 code: []u8,639 code: []u8,
639 macho_file: *MachO,640 macho_file: *MachO,
640 bw: *Writer,641 writer: anytype,
641) Writer.Error!void {642) ResolveError!void {
642 const t = &macho_file.base.comp.root_mod.resolved_target.result;643 const t = &macho_file.base.comp.root_mod.resolved_target.result;
643 const cpu_arch = t.cpu.arch;644 const cpu_arch = t.cpu.arch;
644 const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;645 const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;
...@@ -652,7 +653,7 @@ fn resolveRelocInner(...@@ -652,7 +653,7 @@ fn resolveRelocInner(
652 const divExact = struct {653 const divExact = struct {
653 fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {654 fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {
654 return math.divExact(u12, num, den) catch {655 return math.divExact(u12, num, den) catch {
655 try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {f} at offset 0x{x}", .{656 try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {s} at offset 0x{x}", .{
656 atom.getName(ctx),657 atom.getName(ctx),
657 r.fmtPretty(ctx.getTarget().cpu.arch),658 r.fmtPretty(ctx.getTarget().cpu.arch),
658 r.offset,659 r.offset,
...@@ -689,14 +690,14 @@ fn resolveRelocInner(...@@ -689,14 +690,14 @@ fn resolveRelocInner(
689 if (rel.tag == .@"extern") {690 if (rel.tag == .@"extern") {
690 const sym = rel.getTargetSymbol(self, macho_file);691 const sym = rel.getTargetSymbol(self, macho_file);
691 if (sym.isTlvInit(macho_file)) {692 if (sym.isTlvInit(macho_file)) {
692 try bw.writeInt(u64, @intCast(S - TLS), .little);693 try writer.writeInt(u64, @intCast(S - TLS), .little);
693 return;694 return;
694 }695 }
695 if (sym.flags.import) return;696 if (sym.flags.import) return;
696 }697 }
697 try bw.writeInt(u64, @bitCast(S + A - SUB), .little);698 try writer.writeInt(u64, @bitCast(S + A - SUB), .little);
698 } else if (rel.meta.length == 2) {699 } else if (rel.meta.length == 2) {
699 try bw.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little);700 try writer.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little);
700 } else unreachable;701 } else unreachable;
701 },702 },
702703
...@@ -704,7 +705,7 @@ fn resolveRelocInner(...@@ -704,7 +705,7 @@ fn resolveRelocInner(
704 assert(rel.tag == .@"extern");705 assert(rel.tag == .@"extern");
705 assert(rel.meta.length == 2);706 assert(rel.meta.length == 2);
706 assert(rel.meta.pcrel);707 assert(rel.meta.pcrel);
707 try bw.writeInt(i32, @intCast(G + A - P), .little);708 try writer.writeInt(i32, @intCast(G + A - P), .little);
708 },709 },
709710
710 .branch => {711 .branch => {
...@@ -713,7 +714,7 @@ fn resolveRelocInner(...@@ -713,7 +714,7 @@ fn resolveRelocInner(
713 assert(rel.tag == .@"extern");714 assert(rel.tag == .@"extern");
714715
715 switch (cpu_arch) {716 switch (cpu_arch) {
716 .x86_64 => try bw.writeInt(i32, @intCast(S + A - P), .little),717 .x86_64 => try writer.writeInt(i32, @intCast(S + A - P), .little),
717 .aarch64 => {718 .aarch64 => {
718 const disp: i28 = math.cast(i28, S + A - P) orelse blk: {719 const disp: i28 = math.cast(i28, S + A - P) orelse blk: {
719 const thunk = self.getThunk(macho_file);720 const thunk = self.getThunk(macho_file);
...@@ -731,10 +732,10 @@ fn resolveRelocInner(...@@ -731,10 +732,10 @@ fn resolveRelocInner(
731 assert(rel.meta.length == 2);732 assert(rel.meta.length == 2);
732 assert(rel.meta.pcrel);733 assert(rel.meta.pcrel);
733 if (rel.getTargetSymbol(self, macho_file).getSectionFlags().has_got) {734 if (rel.getTargetSymbol(self, macho_file).getSectionFlags().has_got) {
734 try bw.writeInt(i32, @intCast(G + A - P), .little);735 try writer.writeInt(i32, @intCast(G + A - P), .little);
735 } else {736 } else {
736 try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file);737 try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file);
737 try bw.writeInt(i32, @intCast(S + A - P), .little);738 try writer.writeInt(i32, @intCast(S + A - P), .little);
738 }739 }
739 },740 },
740741
...@@ -745,17 +746,17 @@ fn resolveRelocInner(...@@ -745,17 +746,17 @@ fn resolveRelocInner(
745 const sym = rel.getTargetSymbol(self, macho_file);746 const sym = rel.getTargetSymbol(self, macho_file);
746 if (sym.getSectionFlags().tlv_ptr) {747 if (sym.getSectionFlags().tlv_ptr) {
747 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));748 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));
748 try bw.writeInt(i32, @intCast(S_ + A - P), .little);749 try writer.writeInt(i32, @intCast(S_ + A - P), .little);
749 } else {750 } else {
750 try x86_64.relaxTlv(code[rel_offset - 3 ..], t);751 try x86_64.relaxTlv(code[rel_offset - 3 ..], t);
751 try bw.writeInt(i32, @intCast(S + A - P), .little);752 try writer.writeInt(i32, @intCast(S + A - P), .little);
752 }753 }
753 },754 },
754755
755 .signed, .signed1, .signed2, .signed4 => {756 .signed, .signed1, .signed2, .signed4 => {
756 assert(rel.meta.length == 2);757 assert(rel.meta.length == 2);
757 assert(rel.meta.pcrel);758 assert(rel.meta.pcrel);
758 try bw.writeInt(i32, @intCast(S + A - P), .little);759 try writer.writeInt(i32, @intCast(S + A - P), .little);
759 },760 },
760761
761 .page,762 .page,
...@@ -807,7 +808,7 @@ fn resolveRelocInner(...@@ -807,7 +808,7 @@ fn resolveRelocInner(
807 2 => try divExact(self, rel, @truncate(target), 4, macho_file),808 2 => try divExact(self, rel, @truncate(target), 4, macho_file),
808 3 => try divExact(self, rel, @truncate(target), 8, macho_file),809 3 => try divExact(self, rel, @truncate(target), 8, macho_file),
809 };810 };
810 try bw.writeInt(u32, inst.toU32(), .little);811 try writer.writeInt(u32, inst.toU32(), .little);
811 }812 }
812 },813 },
813814
...@@ -885,7 +886,7 @@ fn resolveRelocInner(...@@ -885,7 +886,7 @@ fn resolveRelocInner(
885 .sf = @as(u1, @truncate(reg_info.size)),886 .sf = @as(u1, @truncate(reg_info.size)),
886 },887 },
887 };888 };
888 try bw.writeInt(u32, inst.toU32(), .little);889 try writer.writeInt(u32, inst.toU32(), .little);
889 },890 },
890 }891 }
891}892}
...@@ -937,8 +938,11 @@ const x86_64 = struct {...@@ -937,8 +938,11 @@ const x86_64 = struct {
937 }938 }
938939
939 fn encode(insts: []const Instruction, code: []u8) !void {940 fn encode(insts: []const Instruction, code: []u8) !void {
940 var bw: Writer = .fixed(code);941 var stream = std.io.fixedBufferStream(code);
941 for (insts) |inst| try inst.encode(&bw, .{});942 const writer = stream.writer();
943 for (insts) |inst| {
944 try inst.encode(writer, .{});
945 }
942 }946 }
943947
944 const bits = @import("../../arch/x86_64/bits.zig");948 const bits = @import("../../arch/x86_64/bits.zig");
src/link/MachO/CodeSignature.zig+9-11
...@@ -247,7 +247,7 @@ pub fn deinit(self: *CodeSignature, allocator: Allocator) void {...@@ -247,7 +247,7 @@ pub fn deinit(self: *CodeSignature, allocator: Allocator) void {
247pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void {247pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void {
248 const file = try fs.cwd().openFile(path, .{});248 const file = try fs.cwd().openFile(path, .{});
249 defer file.close();249 defer file.close();
250 const inner = try file.readToEndAlloc(allocator, .unlimited);250 const inner = try file.readToEndAlloc(allocator, std.math.maxInt(u32));
251 self.entitlements = .{ .inner = inner };251 self.entitlements = .{ .inner = inner };
252}252}
253253
...@@ -304,11 +304,10 @@ pub fn writeAdhocSignature(...@@ -304,11 +304,10 @@ pub fn writeAdhocSignature(
304 var hash: [hash_size]u8 = undefined;304 var hash: [hash_size]u8 = undefined;
305305
306 if (self.requirements) |*req| {306 if (self.requirements) |*req| {
307 var aw: std.io.Writer.Allocating = .init(allocator);307 var buf = std.ArrayList(u8).init(allocator);
308 defer aw.deinit();308 defer buf.deinit();
309309 try req.write(buf.writer());
310 try req.write(&aw.writer);310 Sha256.hash(buf.items, &hash, .{});
311 Sha256.hash(aw.getWritten(), &hash, .{});
312 self.code_directory.addSpecialHash(req.slotType(), hash);311 self.code_directory.addSpecialHash(req.slotType(), hash);
313312
314 try blobs.append(.{ .requirements = req });313 try blobs.append(.{ .requirements = req });
...@@ -317,11 +316,10 @@ pub fn writeAdhocSignature(...@@ -317,11 +316,10 @@ pub fn writeAdhocSignature(
317 }316 }
318317
319 if (self.entitlements) |*ents| {318 if (self.entitlements) |*ents| {
320 var aw: std.io.Writer.Allocating = .init(allocator);319 var buf = std.ArrayList(u8).init(allocator);
321 defer aw.deinit();320 defer buf.deinit();
322321 try ents.write(buf.writer());
323 try ents.write(&aw.writer);322 Sha256.hash(buf.items, &hash, .{});
324 Sha256.hash(aw.getWritten(), &hash, .{});
325 self.code_directory.addSpecialHash(ents.slotType(), hash);323 self.code_directory.addSpecialHash(ents.slotType(), hash);
326324
327 try blobs.append(.{ .entitlements = ents });325 try blobs.append(.{ .entitlements = ents });
src/link/MachO/DebugSymbols.zig+16-11
...@@ -269,14 +269,18 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {...@@ -269,14 +269,18 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
269269
270fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } {270fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } {
271 const gpa = self.allocator;271 const gpa = self.allocator;
272 var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeDsym(macho_file, self)));272 const needed_size = load_commands.calcLoadCommandsSizeDsym(macho_file, self);
273 defer gpa.free(bw.buffer);273 const buffer = try gpa.alloc(u8, needed_size);
274 defer gpa.free(buffer);
275
276 var stream = std.io.fixedBufferStream(buffer);
277 const writer = stream.writer();
274278
275 var ncmds: usize = 0;279 var ncmds: usize = 0;
276280
277 // UUID comes first presumably to speed up lookup by the consumer like lldb.281 // UUID comes first presumably to speed up lookup by the consumer like lldb.
278 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);282 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);
279 try bw.writeStruct(self.uuid_cmd);283 try writer.writeStruct(self.uuid_cmd);
280 ncmds += 1;284 ncmds += 1;
281285
282 // Segment and section load commands286 // Segment and section load commands
...@@ -289,11 +293,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -289,11 +293,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
289 var out_seg = seg;293 var out_seg = seg;
290 out_seg.fileoff = 0;294 out_seg.fileoff = 0;
291 out_seg.filesize = 0;295 out_seg.filesize = 0;
292 try bw.writeStruct(out_seg);296 try writer.writeStruct(out_seg);
293 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {297 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
294 var out_header = header;298 var out_header = header;
295 out_header.offset = 0;299 out_header.offset = 0;
296 try bw.writeStruct(out_header);300 try writer.writeStruct(out_header);
297 }301 }
298 sect_id += seg.nsects;302 sect_id += seg.nsects;
299 }303 }
...@@ -302,22 +306,23 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -302,22 +306,23 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
302 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.306 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
303 sect_id = 0;307 sect_id = 0;
304 for (self.segments.items) |seg| {308 for (self.segments.items) |seg| {
305 try bw.writeStruct(seg);309 try writer.writeStruct(seg);
306 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {310 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
307 try bw.writeStruct(header);311 try writer.writeStruct(header);
308 }312 }
309 sect_id += seg.nsects;313 sect_id += seg.nsects;
310 }314 }
311 ncmds += self.segments.items.len;315 ncmds += self.segments.items.len;
312 }316 }
313317
314 try bw.writeStruct(self.symtab_cmd);318 try writer.writeStruct(self.symtab_cmd);
315 ncmds += 1;319 ncmds += 1;
316320
317 assert(bw.end == bw.buffer.len);321 assert(stream.pos == needed_size);
318 try self.file.?.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));322
323 try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
319324
320 return .{ ncmds, bw.end };325 return .{ ncmds, buffer.len };
321}326}
322327
323fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {328fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
src/link/MachO/Dwarf.zig+30-18
...@@ -81,7 +81,7 @@ pub const InfoReader = struct {...@@ -81,7 +81,7 @@ pub const InfoReader = struct {
81 .dwarf64 => 12,81 .dwarf64 => 12,
82 } + cuh_length;82 } + cuh_length;
83 while (p.pos < end_pos) {83 while (p.pos < end_pos) {
84 const di_code = try p.readLeb128(u64);84 const di_code = try p.readUleb128(u64);
85 if (di_code == 0) return error.UnexpectedEndOfFile;85 if (di_code == 0) return error.UnexpectedEndOfFile;
86 if (di_code == code) return;86 if (di_code == code) return;
8787
...@@ -174,14 +174,14 @@ pub const InfoReader = struct {...@@ -174,14 +174,14 @@ pub const InfoReader = struct {
174 dw.FORM.block1 => try p.readByte(),174 dw.FORM.block1 => try p.readByte(),
175 dw.FORM.block2 => try p.readInt(u16),175 dw.FORM.block2 => try p.readInt(u16),
176 dw.FORM.block4 => try p.readInt(u32),176 dw.FORM.block4 => try p.readInt(u32),
177 dw.FORM.block => try p.readLeb128(u64),177 dw.FORM.block => try p.readUleb128(u64),
178 else => unreachable,178 else => unreachable,
179 };179 };
180 return p.readNBytes(len);180 return p.readNBytes(len);
181 }181 }
182182
183 pub fn readExprLoc(p: *InfoReader) ![]const u8 {183 pub fn readExprLoc(p: *InfoReader) ![]const u8 {
184 const len: u64 = try p.readLeb128(u64);184 const len: u64 = try p.readUleb128(u64);
185 return p.readNBytes(len);185 return p.readNBytes(len);
186 }186 }
187187
...@@ -191,8 +191,8 @@ pub const InfoReader = struct {...@@ -191,8 +191,8 @@ pub const InfoReader = struct {
191 dw.FORM.data2, dw.FORM.ref2 => try p.readInt(u16),191 dw.FORM.data2, dw.FORM.ref2 => try p.readInt(u16),
192 dw.FORM.data4, dw.FORM.ref4 => try p.readInt(u32),192 dw.FORM.data4, dw.FORM.ref4 => try p.readInt(u32),
193 dw.FORM.data8, dw.FORM.ref8, dw.FORM.ref_sig8 => try p.readInt(u64),193 dw.FORM.data8, dw.FORM.ref8, dw.FORM.ref_sig8 => try p.readInt(u64),
194 dw.FORM.udata, dw.FORM.ref_udata => try p.readLeb128(u64),194 dw.FORM.udata, dw.FORM.ref_udata => try p.readUleb128(u64),
195 dw.FORM.sdata => @bitCast(try p.readLeb128(i64)),195 dw.FORM.sdata => @bitCast(try p.readIleb128(i64)),
196 else => return error.UnhandledConstantForm,196 else => return error.UnhandledConstantForm,
197 };197 };
198 }198 }
...@@ -203,7 +203,7 @@ pub const InfoReader = struct {...@@ -203,7 +203,7 @@ pub const InfoReader = struct {
203 dw.FORM.strx2, dw.FORM.addrx2 => try p.readInt(u16),203 dw.FORM.strx2, dw.FORM.addrx2 => try p.readInt(u16),
204 dw.FORM.strx3, dw.FORM.addrx3 => error.UnhandledForm,204 dw.FORM.strx3, dw.FORM.addrx3 => error.UnhandledForm,
205 dw.FORM.strx4, dw.FORM.addrx4 => try p.readInt(u32),205 dw.FORM.strx4, dw.FORM.addrx4 => try p.readInt(u32),
206 dw.FORM.strx, dw.FORM.addrx => try p.readLeb128(u64),206 dw.FORM.strx, dw.FORM.addrx => try p.readUleb128(u64),
207 else => return error.UnhandledIndexForm,207 else => return error.UnhandledIndexForm,
208 };208 };
209 }209 }
...@@ -272,10 +272,20 @@ pub const InfoReader = struct {...@@ -272,10 +272,20 @@ pub const InfoReader = struct {
272 };272 };
273 }273 }
274274
275 pub fn readLeb128(p: *InfoReader, comptime Type: type) !Type {275 pub fn readUleb128(p: *InfoReader, comptime Type: type) !Type {
276 var r: std.io.Reader = .fixed(p.bytes()[p.pos..]);276 var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
277 defer p.pos += r.seek;277 var creader = std.io.countingReader(stream.reader());
278 return r.takeLeb128(Type);278 const value: Type = try leb.readUleb128(Type, creader.reader());
279 p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
280 return value;
281 }
282
283 pub fn readIleb128(p: *InfoReader, comptime Type: type) !Type {
284 var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
285 var creader = std.io.countingReader(stream.reader());
286 const value: Type = try leb.readIleb128(Type, creader.reader());
287 p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
288 return value;
279 }289 }
280290
281 pub fn seekTo(p: *InfoReader, off: u64) !void {291 pub fn seekTo(p: *InfoReader, off: u64) !void {
...@@ -297,10 +307,10 @@ pub const AbbrevReader = struct {...@@ -297,10 +307,10 @@ pub const AbbrevReader = struct {
297307
298 pub fn readDecl(p: *AbbrevReader) !?AbbrevDecl {308 pub fn readDecl(p: *AbbrevReader) !?AbbrevDecl {
299 const pos = p.pos;309 const pos = p.pos;
300 const code = try p.readLeb128(Code);310 const code = try p.readUleb128(Code);
301 if (code == 0) return null;311 if (code == 0) return null;
302312
303 const tag = try p.readLeb128(Tag);313 const tag = try p.readUleb128(Tag);
304 const has_children = (try p.readByte()) > 0;314 const has_children = (try p.readByte()) > 0;
305 return .{315 return .{
306 .code = code,316 .code = code,
...@@ -313,8 +323,8 @@ pub const AbbrevReader = struct {...@@ -313,8 +323,8 @@ pub const AbbrevReader = struct {
313323
314 pub fn readAttr(p: *AbbrevReader) !?AbbrevAttr {324 pub fn readAttr(p: *AbbrevReader) !?AbbrevAttr {
315 const pos = p.pos;325 const pos = p.pos;
316 const at = try p.readLeb128(At);326 const at = try p.readUleb128(At);
317 const form = try p.readLeb128(Form);327 const form = try p.readUleb128(Form);
318 return if (at == 0 and form == 0) null else .{328 return if (at == 0 and form == 0) null else .{
319 .at = at,329 .at = at,
320 .form = form,330 .form = form,
...@@ -329,10 +339,12 @@ pub const AbbrevReader = struct {...@@ -329,10 +339,12 @@ pub const AbbrevReader = struct {
329 return p.bytes()[p.pos];339 return p.bytes()[p.pos];
330 }340 }
331341
332 pub fn readLeb128(p: *AbbrevReader, comptime Type: type) !Type {342 pub fn readUleb128(p: *AbbrevReader, comptime Type: type) !Type {
333 var r: std.io.Reader = .fixed(p.bytes()[p.pos..]);343 var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
334 defer p.pos += r.seek;344 var creader = std.io.countingReader(stream.reader());
335 return r.takeLeb128(Type);345 const value: Type = try leb.readUleb128(Type, creader.reader());
346 p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
347 return value;
336 }348 }
337349
338 pub fn seekTo(p: *AbbrevReader, off: u64) !void {350 pub fn seekTo(p: *AbbrevReader, off: u64) !void {
src/link/MachO/Dylib.zig+58-17
...@@ -158,6 +158,46 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {...@@ -158,6 +158,46 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
158 }158 }
159}159}
160160
161const TrieIterator = struct {
162 data: []const u8,
163 pos: usize = 0,
164
165 fn getStream(it: *TrieIterator) std.io.FixedBufferStream([]const u8) {
166 return std.io.fixedBufferStream(it.data[it.pos..]);
167 }
168
169 fn readUleb128(it: *TrieIterator) !u64 {
170 var stream = it.getStream();
171 var creader = std.io.countingReader(stream.reader());
172 const reader = creader.reader();
173 const value = try std.leb.readUleb128(u64, reader);
174 it.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
175 return value;
176 }
177
178 fn readString(it: *TrieIterator) ![:0]const u8 {
179 var stream = it.getStream();
180 const reader = stream.reader();
181
182 var count: usize = 0;
183 while (true) : (count += 1) {
184 const byte = try reader.readByte();
185 if (byte == 0) break;
186 }
187
188 const str = @as([*:0]const u8, @ptrCast(it.data.ptr + it.pos))[0..count :0];
189 it.pos += count + 1;
190 return str;
191 }
192
193 fn readByte(it: *TrieIterator) !u8 {
194 var stream = it.getStream();
195 const value = try stream.reader().readByte();
196 it.pos += 1;
197 return value;
198 }
199};
200
161pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void {201pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void {
162 try self.exports.append(allocator, .{202 try self.exports.append(allocator, .{
163 .name = try self.addString(allocator, name),203 .name = try self.addString(allocator, name),
...@@ -167,16 +207,16 @@ pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Ex...@@ -167,16 +207,16 @@ pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Ex
167207
168fn parseTrieNode(208fn parseTrieNode(
169 self: *Dylib,209 self: *Dylib,
170 br: *std.io.Reader,210 it: *TrieIterator,
171 allocator: Allocator,211 allocator: Allocator,
172 arena: Allocator,212 arena: Allocator,
173 prefix: []const u8,213 prefix: []const u8,
174) !void {214) !void {
175 const tracy = trace(@src());215 const tracy = trace(@src());
176 defer tracy.end();216 defer tracy.end();
177 const size = try br.takeLeb128(u64);217 const size = try it.readUleb128();
178 if (size > 0) {218 if (size > 0) {
179 const flags = try br.takeLeb128(u8);219 const flags = try it.readUleb128();
180 const kind = flags & macho.EXPORT_SYMBOL_FLAGS_KIND_MASK;220 const kind = flags & macho.EXPORT_SYMBOL_FLAGS_KIND_MASK;
181 const out_flags = Export.Flags{221 const out_flags = Export.Flags{
182 .abs = kind == macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE,222 .abs = kind == macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE,
...@@ -184,28 +224,29 @@ fn parseTrieNode(...@@ -184,28 +224,29 @@ fn parseTrieNode(
184 .weak = flags & macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION != 0,224 .weak = flags & macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION != 0,
185 };225 };
186 if (flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT != 0) {226 if (flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT != 0) {
187 _ = try br.takeLeb128(u64); // dylib ordinal227 _ = try it.readUleb128(); // dylib ordinal
188 const name = try br.takeSentinel(0);228 const name = try it.readString();
189 try self.addExport(allocator, if (name.len > 0) name else prefix, out_flags);229 try self.addExport(allocator, if (name.len > 0) name else prefix, out_flags);
190 } else if (flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER != 0) {230 } else if (flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER != 0) {
191 _ = try br.takeLeb128(u64); // stub offset231 _ = try it.readUleb128(); // stub offset
192 _ = try br.takeLeb128(u64); // resolver offset232 _ = try it.readUleb128(); // resolver offset
193 try self.addExport(allocator, prefix, out_flags);233 try self.addExport(allocator, prefix, out_flags);
194 } else {234 } else {
195 _ = try br.takeLeb128(u64); // VM offset235 _ = try it.readUleb128(); // VM offset
196 try self.addExport(allocator, prefix, out_flags);236 try self.addExport(allocator, prefix, out_flags);
197 }237 }
198 }238 }
199239
200 const nedges = try br.takeByte();240 const nedges = try it.readByte();
241
201 for (0..nedges) |_| {242 for (0..nedges) |_| {
202 const label = try br.takeSentinel(0);243 const label = try it.readString();
203 const off = try br.takeLeb128(usize);244 const off = try it.readUleb128();
204 const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label });245 const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label });
205 const seek = br.seek;246 const curr = it.pos;
206 br.seek = off;247 it.pos = math.cast(usize, off) orelse return error.Overflow;
207 try self.parseTrieNode(br, allocator, arena, prefix_label);248 try self.parseTrieNode(it, allocator, arena, prefix_label);
208 br.seek = seek;249 it.pos = curr;
209 }250 }
210}251}
211252
...@@ -216,8 +257,8 @@ fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void {...@@ -216,8 +257,8 @@ fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void {
216 var arena = std.heap.ArenaAllocator.init(gpa);257 var arena = std.heap.ArenaAllocator.init(gpa);
217 defer arena.deinit();258 defer arena.deinit();
218259
219 var r: std.io.Reader = .fixed(data);260 var it: TrieIterator = .{ .data = data };
220 try self.parseTrieNode(&r, gpa, arena.allocator(), "");261 try self.parseTrieNode(&it, gpa, arena.allocator(), "");
221}262}
222263
223fn parseTbd(self: *Dylib, macho_file: *MachO) !void {264fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
src/link/MachO/InternalObject.zig+1-1
...@@ -261,7 +261,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil...@@ -261,7 +261,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
261261
262 sect.offset = @intCast(self.objc_methnames.items.len);262 sect.offset = @intCast(self.objc_methnames.items.len);
263 try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);263 try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);
264 self.objc_methnames.print(gpa, "{s}\x00", .{methname}) catch unreachable;264 self.objc_methnames.writer(gpa).print("{s}\x00", .{methname}) catch unreachable;
265265
266 const name_str = try self.addString(gpa, "ltmp");266 const name_str = try self.addString(gpa, "ltmp");
267 const sym_index = try self.addSymbol(gpa);267 const sym_index = try self.addSymbol(gpa);
src/link/MachO/Object.zig+5-5
...@@ -1069,7 +1069,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi...@@ -1069,7 +1069,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi
1069 }1069 }
1070 }1070 }
10711071
1072 var it: eh_frame.Iterator = .{ .br = .fixed(self.eh_frame_data.items) };1072 var it = eh_frame.Iterator{ .data = self.eh_frame_data.items };
1073 while (try it.next()) |rec| {1073 while (try it.next()) |rec| {
1074 switch (rec.tag) {1074 switch (rec.tag) {
1075 .cie => try self.cies.append(allocator, .{1075 .cie => try self.cies.append(allocator, .{
...@@ -1698,11 +1698,11 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {...@@ -1698,11 +1698,11 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
1698 };1698 };
1699}1699}
17001700
1701pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) !void {1701pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
1702 // Header1702 // Header
1703 const size = try macho_file.cast(usize, self.output_ar_state.size);1703 const size = try macho_file.cast(usize, self.output_ar_state.size);
1704 const basename = std.fs.path.basename(self.path.sub_path);1704 const basename = std.fs.path.basename(self.path.sub_path);
1705 try Archive.writeHeader(bw, basename, size, ar_format);1705 try Archive.writeHeader(basename, size, ar_format, writer);
1706 // Data1706 // Data
1707 const file = macho_file.getFileHandle(self.file_handle);1707 const file = macho_file.getFileHandle(self.file_handle);
1708 // TODO try using copyRangeAll1708 // TODO try using copyRangeAll
...@@ -1711,7 +1711,7 @@ pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file:...@@ -1711,7 +1711,7 @@ pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file:
1711 defer gpa.free(data);1711 defer gpa.free(data);
1712 const amt = try file.preadAll(data, self.offset);1712 const amt = try file.preadAll(data, self.offset);
1713 if (amt != size) return error.InputOutput;1713 if (amt != size) return error.InputOutput;
1714 try bw.writeAll(data);1714 try writer.writeAll(data);
1715}1715}
17161716
1717pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {1717pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
...@@ -1865,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {...@@ -1865,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
1865 }1865 }
1866 gpa.free(sections_data);1866 gpa.free(sections_data);
1867 }1867 }
1868 @memset(sections_data, &.{});1868 @memset(sections_data, &[0]u8{});
1869 const file = macho_file.getFileHandle(self.file_handle);1869 const file = macho_file.getFileHandle(self.file_handle);
18701870
1871 for (headers, 0..) |header, n_sect| {1871 for (headers, 0..) |header, n_sect| {
src/link/MachO/Symbol.zig+1-1
...@@ -297,7 +297,7 @@ const Format = struct {...@@ -297,7 +297,7 @@ const Format = struct {
297 symbol: Symbol,297 symbol: Symbol,
298 macho_file: *MachO,298 macho_file: *MachO,
299299
300 fn format2(f: Format, w: *Writer) Writer.Error!void {300 fn default(f: Format, w: *Writer) Writer.Error!void {
301 const symbol = f.symbol;301 const symbol = f.symbol;
302 try w.print("%{d} : {s} : @{x}", .{302 try w.print("%{d} : {s} : @{x}", .{
303 symbol.nlist_idx,303 symbol.nlist_idx,
src/link/MachO/Thunk.zig+4-4
...@@ -20,16 +20,16 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {...@@ -20,16 +20,16 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
20 return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;20 return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;
21}21}
2222
23pub fn write(thunk: Thunk, macho_file: *MachO, bw: *Writer) !void {23pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
24 for (thunk.symbols.keys(), 0..) |ref, i| {24 for (thunk.symbols.keys(), 0..) |ref, i| {
25 const sym = ref.getSymbol(macho_file).?;25 const sym = ref.getSymbol(macho_file).?;
26 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;26 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
27 const taddr = sym.getAddress(.{}, macho_file);27 const taddr = sym.getAddress(.{}, macho_file);
28 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));28 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
29 try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);29 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
30 const off: u12 = @truncate(taddr);30 const off: u12 = @truncate(taddr);
31 try bw.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);31 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
32 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);32 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
33 }33 }
34}34}
3535
src/link/MachO/UnwindInfo.zig+18-12
...@@ -289,10 +289,13 @@ pub fn calcSize(info: UnwindInfo) usize {...@@ -289,10 +289,13 @@ pub fn calcSize(info: UnwindInfo) usize {
289 return total_size;289 return total_size;
290}290}
291291
292pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!void {292pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
293 const seg = macho_file.getTextSegment();293 const seg = macho_file.getTextSegment();
294 const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];294 const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];
295295
296 var stream = std.io.fixedBufferStream(buffer);
297 const writer = stream.writer();
298
296 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);299 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);
297 const common_encodings_count: u32 = info.common_encodings_count;300 const common_encodings_count: u32 = info.common_encodings_count;
298 const personalities_offset: u32 = common_encodings_offset + common_encodings_count * @sizeOf(u32);301 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...@@ -300,7 +303,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
300 const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);303 const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);
301 const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));304 const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));
302305
303 try bw.writeStruct(macho.unwind_info_section_header{306 try writer.writeStruct(macho.unwind_info_section_header{
304 .commonEncodingsArraySectionOffset = common_encodings_offset,307 .commonEncodingsArraySectionOffset = common_encodings_offset,
305 .commonEncodingsArrayCount = common_encodings_count,308 .commonEncodingsArrayCount = common_encodings_count,
306 .personalityArraySectionOffset = personalities_offset,309 .personalityArraySectionOffset = personalities_offset,
...@@ -309,11 +312,11 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi...@@ -309,11 +312,11 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
309 .indexCount = indexes_count,312 .indexCount = indexes_count,
310 });313 });
311314
312 try bw.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));315 try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));
313316
314 for (info.personalities[0..info.personalities_count]) |ref| {317 for (info.personalities[0..info.personalities_count]) |ref| {
315 const sym = ref.getSymbol(macho_file).?;318 const sym = ref.getSymbol(macho_file).?;
316 try bw.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little);319 try writer.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little);
317 }320 }
318321
319 const pages_base_offset = @as(u32, @intCast(header.size - (info.pages.items.len * second_level_page_bytes)));322 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...@@ -322,7 +325,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
322 for (info.pages.items, 0..) |page, i| {325 for (info.pages.items, 0..) |page, i| {
323 assert(page.count > 0);326 assert(page.count > 0);
324 const rec = info.records.items[page.start].getUnwindRecord(macho_file);327 const rec = info.records.items[page.start].getUnwindRecord(macho_file);
325 try bw.writeStruct(macho.unwind_info_section_header_index_entry{328 try writer.writeStruct(macho.unwind_info_section_header_index_entry{
326 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),329 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
327 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),330 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
328 .lsdaIndexArraySectionOffset = lsda_base_offset +331 .lsdaIndexArraySectionOffset = lsda_base_offset +
...@@ -332,7 +335,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi...@@ -332,7 +335,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
332335
333 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);336 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);
334 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));337 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));
335 try bw.writeStruct(macho.unwind_info_section_header_index_entry{338 try writer.writeStruct(macho.unwind_info_section_header_index_entry{
336 .functionOffset = sentinel_address,339 .functionOffset = sentinel_address,
337 .secondLevelPagesSectionOffset = 0,340 .secondLevelPagesSectionOffset = 0,
338 .lsdaIndexArraySectionOffset = lsda_base_offset +341 .lsdaIndexArraySectionOffset = lsda_base_offset +
...@@ -341,20 +344,23 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi...@@ -341,20 +344,23 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
341344
342 for (info.lsdas.items) |index| {345 for (info.lsdas.items) |index| {
343 const rec = info.records.items[index].getUnwindRecord(macho_file);346 const rec = info.records.items[index].getUnwindRecord(macho_file);
344 try bw.writeStruct(macho.unwind_info_section_header_lsda_index_entry{347 try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{
345 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),348 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
346 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),349 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),
347 });350 });
348 }351 }
349352
350 for (info.pages.items) |page| {353 for (info.pages.items) |page| {
351 const start = bw.count;354 const start = stream.pos;
352 try page.write(info, macho_file, bw);355 try page.write(info, macho_file, writer);
353 const nwritten = bw.count - start;356 const nwritten = stream.pos - start;
354 try bw.splatByteAll(0, math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow);357 if (nwritten < second_level_page_bytes) {
358 const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;
359 try writer.writeByteNTimes(0, padding);
360 }
355 }361 }
356362
357 @memset(bw.unusedCapacitySlice(), 0);363 @memset(buffer[stream.pos..], 0);
358}364}
359365
360fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {366fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {
src/link/MachO/ZigObject.zig+5-3
...@@ -317,12 +317,12 @@ pub fn updateArSize(self: *ZigObject) void {...@@ -317,12 +317,12 @@ pub fn updateArSize(self: *ZigObject) void {
317 self.output_ar_state.size = self.data.items.len;317 self.output_ar_state.size = self.data.items.len;
318}318}
319319
320pub fn writeAr(self: ZigObject, bw: *Writer, ar_format: Archive.Format) Writer.Error!void {320pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void {
321 // Header321 // Header
322 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;322 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
323 try Archive.writeHeader(bw, self.basename, size, ar_format);323 try Archive.writeHeader(self.basename, size, ar_format, writer);
324 // Data324 // Data
325 try bw.writeAll(self.data.items);325 try writer.writeAll(self.data.items);
326}326}
327327
328pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void {328pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void {
...@@ -884,6 +884,7 @@ pub fn updateNav(...@@ -884,6 +884,7 @@ pub fn updateNav(
884 defer debug_wip_nav.deinit();884 defer debug_wip_nav.deinit();
885 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {885 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
886 error.OutOfMemory => return error.OutOfMemory,886 error.OutOfMemory => return error.OutOfMemory,
887 error.Overflow => return error.Overflow,
887 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),888 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
888 };889 };
889 }890 }
...@@ -920,6 +921,7 @@ pub fn updateNav(...@@ -920,6 +921,7 @@ pub fn updateNav(
920921
921 if (debug_wip_nav) |*wip_nav| self.dwarf.?.finishWipNav(pt, nav_index, wip_nav) catch |err| switch (err) {922 if (debug_wip_nav) |*wip_nav| self.dwarf.?.finishWipNav(pt, nav_index, wip_nav) catch |err| switch (err) {
922 error.OutOfMemory => return error.OutOfMemory,923 error.OutOfMemory => return error.OutOfMemory,
924 error.Overflow => return error.Overflow,
923 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),925 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
924 };926 };
925 } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index);927 } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index);
src/link/MachO/dyld_info/Rebase.zig+45-45
...@@ -3,7 +3,7 @@ buffer: std.ArrayListUnmanaged(u8) = .empty,...@@ -3,7 +3,7 @@ buffer: std.ArrayListUnmanaged(u8) = .empty,
33
4pub const Entry = struct {4pub const Entry = struct {
5 offset: u64,5 offset: u64,
6 segment_id: u4,6 segment_id: u8,
77
8 pub fn lessThan(ctx: void, entry: Entry, other: Entry) bool {8 pub fn lessThan(ctx: void, entry: Entry, other: Entry) bool {
9 _ = ctx;9 _ = ctx;
...@@ -110,35 +110,33 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {...@@ -110,35 +110,33 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
110fn finalize(rebase: *Rebase, gpa: Allocator) !void {110fn finalize(rebase: *Rebase, gpa: Allocator) !void {
111 if (rebase.entries.items.len == 0) return;111 if (rebase.entries.items.len == 0) return;
112112
113 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &rebase.buffer);113 const writer = rebase.buffer.writer(gpa);
114 const bw = &aw.writer;
115 defer rebase.buffer = aw.toArrayList();
116114
117 log.debug("rebase opcodes", .{});115 log.debug("rebase opcodes", .{});
118116
119 std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);117 std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);
120118
121 try setTypePointer(bw);119 try setTypePointer(writer);
122120
123 var start: usize = 0;121 var start: usize = 0;
124 var seg_id: ?u8 = null;122 var seg_id: ?u8 = null;
125 for (rebase.entries.items, 0..) |entry, i| {123 for (rebase.entries.items, 0..) |entry, i| {
126 if (seg_id != null and seg_id.? == entry.segment_id) continue;124 if (seg_id != null and seg_id.? == entry.segment_id) continue;
127 try finalizeSegment(rebase.entries.items[start..i], bw);125 try finalizeSegment(rebase.entries.items[start..i], writer);
128 seg_id = entry.segment_id;126 seg_id = entry.segment_id;
129 start = i;127 start = i;
130 }128 }
131129
132 try finalizeSegment(rebase.entries.items[start..], bw);130 try finalizeSegment(rebase.entries.items[start..], writer);
133 try done(bw);131 try done(writer);
134}132}
135133
136fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {134fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
137 if (entries.len == 0) return;135 if (entries.len == 0) return;
138136
139 const segment_id = entries[0].segment_id;137 const segment_id = entries[0].segment_id;
140 var offset = entries[0].offset;138 var offset = entries[0].offset;
141 try setSegmentOffset(segment_id, offset, bw);139 try setSegmentOffset(segment_id, offset, writer);
142140
143 var count: usize = 0;141 var count: usize = 0;
144 var skip: u64 = 0;142 var skip: u64 = 0;
...@@ -157,7 +155,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {...@@ -157,7 +155,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
157 .start => {155 .start => {
158 if (offset < current_offset) {156 if (offset < current_offset) {
159 const delta = current_offset - offset;157 const delta = current_offset - offset;
160 try addAddr(delta, bw);158 try addAddr(delta, writer);
161 offset += delta;159 offset += delta;
162 }160 }
163 state = .times;161 state = .times;
...@@ -177,7 +175,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {...@@ -177,7 +175,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
177 offset += skip;175 offset += skip;
178 i -= 1;176 i -= 1;
179 } else {177 } else {
180 try rebaseTimes(count, bw);178 try rebaseTimes(count, writer);
181 state = .start;179 state = .start;
182 i -= 1;180 i -= 1;
183 }181 }
...@@ -186,9 +184,9 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {...@@ -186,9 +184,9 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
186 if (current_offset < offset) {184 if (current_offset < offset) {
187 count -= 1;185 count -= 1;
188 if (count == 1) {186 if (count == 1) {
189 try rebaseAddAddr(skip, bw);187 try rebaseAddAddr(skip, writer);
190 } else {188 } else {
191 try rebaseTimesSkip(count, skip, bw);189 try rebaseTimesSkip(count, skip, writer);
192 }190 }
193 state = .start;191 state = .start;
194 offset = offset - (@sizeOf(u64) + skip);192 offset = offset - (@sizeOf(u64) + skip);
...@@ -201,7 +199,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {...@@ -201,7 +199,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
201 count += 1;199 count += 1;
202 offset += @sizeOf(u64) + skip;200 offset += @sizeOf(u64) + skip;
203 } else {201 } else {
204 try rebaseTimesSkip(count, skip, bw);202 try rebaseTimesSkip(count, skip, writer);
205 state = .start;203 state = .start;
206 i -= 1;204 i -= 1;
207 }205 }
...@@ -212,66 +210,68 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {...@@ -212,66 +210,68 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
212 switch (state) {210 switch (state) {
213 .start => unreachable,211 .start => unreachable,
214 .times => {212 .times => {
215 try rebaseTimes(count, bw);213 try rebaseTimes(count, writer);
216 },214 },
217 .times_skip => {215 .times_skip => {
218 try rebaseTimesSkip(count, skip, bw);216 try rebaseTimesSkip(count, skip, writer);
219 },217 },
220 }218 }
221}219}
222220
223fn setTypePointer(bw: *Writer) Writer.Error!void {221fn setTypePointer(writer: anytype) !void {
224 log.debug(">>> set type: {d}", .{macho.REBASE_TYPE_POINTER});222 log.debug(">>> set type: {d}", .{macho.REBASE_TYPE_POINTER});
225 try bw.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.REBASE_TYPE_POINTER)));223 try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.REBASE_TYPE_POINTER)));
226}224}
227225
228fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {226fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
229 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });227 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
230 try bw.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));228 try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
231 try bw.writeLeb128(offset);229 try std.leb.writeUleb128(writer, offset);
232}230}
233231
234fn rebaseAddAddr(addr: u64, bw: *Writer) Writer.Error!void {232fn rebaseAddAddr(addr: u64, writer: anytype) !void {
235 log.debug(">>> rebase with add: {x}", .{addr});233 log.debug(">>> rebase with add: {x}", .{addr});
236 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);234 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
237 try bw.writeLeb128(addr);235 try std.leb.writeUleb128(writer, addr);
238}236}
239237
240fn rebaseTimes(count: usize, bw: *Writer) Writer.Error!void {238fn rebaseTimes(count: usize, writer: anytype) !void {
241 log.debug(">>> rebase with count: {d}", .{count});239 log.debug(">>> rebase with count: {d}", .{count});
242 if (count <= 0xf) {240 if (count <= 0xf) {
243 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count)));241 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count)));
244 } else {242 } else {
245 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);243 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
246 try bw.writeLeb128(count);244 try std.leb.writeUleb128(writer, count);
247 }245 }
248}246}
249247
250fn rebaseTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {248fn rebaseTimesSkip(count: usize, skip: u64, writer: anytype) !void {
251 log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip });249 log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip });
252 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);250 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
253 try bw.writeLeb128(count);251 try std.leb.writeUleb128(writer, count);
254 try bw.writeLeb128(skip);252 try std.leb.writeUleb128(writer, skip);
255}253}
256254
257fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {255fn addAddr(addr: u64, writer: anytype) !void {
258 log.debug(">>> add: {x}", .{addr});256 log.debug(">>> add: {x}", .{addr});
259 if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| {257 if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {
260 if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte(258 const imm = @divExact(addr, @sizeOf(u64));
261 macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | imm_scaled,259 if (imm <= 0xf) {
262 );260 try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)));
263 } else |_| {}261 return;
264 try bw.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);262 }
265 try bw.writeLeb128(addr);263 }
264 try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);
265 try std.leb.writeUleb128(writer, addr);
266}266}
267267
268fn done(bw: *Writer) Writer.Error!void {268fn done(writer: anytype) !void {
269 log.debug(">>> done", .{});269 log.debug(">>> done", .{});
270 try bw.writeByte(macho.REBASE_OPCODE_DONE);270 try writer.writeByte(macho.REBASE_OPCODE_DONE);
271}271}
272272
273pub fn write(rebase: Rebase, bw: *Writer) Writer.Error!void {273pub fn write(rebase: Rebase, writer: anytype) !void {
274 try bw.writeAll(rebase.buffer.items);274 try writer.writeAll(rebase.buffer.items);
275}275}
276276
277test "rebase - no entries" {277test "rebase - no entries" {
src/link/MachO/dyld_info/Trie.zig+37-32
...@@ -31,7 +31,7 @@...@@ -31,7 +31,7 @@
3131
32/// The root node of the trie.32/// The root node of the trie.
33root: ?Node.Index = null,33root: ?Node.Index = null,
34buffer: []u8 = &.{},34buffer: std.ArrayListUnmanaged(u8) = .empty,
35nodes: std.MultiArrayList(Node) = .{},35nodes: std.MultiArrayList(Node) = .{},
36edges: std.ArrayListUnmanaged(Edge) = .empty,36edges: std.ArrayListUnmanaged(Edge) = .empty,
3737
...@@ -123,7 +123,7 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void {...@@ -123,7 +123,7 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void {
123123
124 try self.finalize(gpa);124 try self.finalize(gpa);
125125
126 macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.len), @alignOf(u64));126 macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
127}127}
128128
129/// Finalizes this trie for writing to a byte stream.129/// Finalizes this trie for writing to a byte stream.
...@@ -138,7 +138,7 @@ fn finalize(self: *Trie, allocator: Allocator) !void {...@@ -138,7 +138,7 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
138 defer ordered_nodes.deinit();138 defer ordered_nodes.deinit();
139 try ordered_nodes.ensureTotalCapacityPrecise(self.nodes.items(.is_terminal).len);139 try ordered_nodes.ensureTotalCapacityPrecise(self.nodes.items(.is_terminal).len);
140140
141 var fifo = DeprecatedLinearFifo(Node.Index).init(allocator);141 var fifo = std.fifo.LinearFifo(Node.Index, .Dynamic).init(allocator);
142 defer fifo.deinit();142 defer fifo.deinit();
143143
144 try fifo.writeItem(self.root.?);144 try fifo.writeItem(self.root.?);
...@@ -164,11 +164,9 @@ fn finalize(self: *Trie, allocator: Allocator) !void {...@@ -164,11 +164,9 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
164 }164 }
165 }165 }
166166
167 assert(self.buffer.len == 0);167 try self.buffer.ensureTotalCapacityPrecise(allocator, size);
168 self.buffer = try allocator.alloc(u8, size);
169 var bw: Writer = .fixed(self.buffer);
170 for (ordered_nodes.items) |node_index| {168 for (ordered_nodes.items) |node_index| {
171 try self.writeNode(node_index, &bw);169 try self.writeNode(node_index, self.buffer.writer(allocator));
172 }170 }
173}171}
174172
...@@ -183,17 +181,17 @@ const FinalizeNodeResult = struct {...@@ -183,17 +181,17 @@ const FinalizeNodeResult = struct {
183181
184/// Updates offset of this node in the output byte stream.182/// Updates offset of this node in the output byte stream.
185fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult {183fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult {
186 var buf: [1024]u8 = undefined;184 var stream = std.io.countingWriter(std.io.null_writer);
187 var bw: Writer = .discarding(&buf);185 const writer = stream.writer();
188 const slice = self.nodes.slice();186 const slice = self.nodes.slice();
189187
190 var node_size: u32 = 0;188 var node_size: u32 = 0;
191 if (slice.items(.is_terminal)[node_index]) {189 if (slice.items(.is_terminal)[node_index]) {
192 const export_flags = slice.items(.export_flags)[node_index];190 const export_flags = slice.items(.export_flags)[node_index];
193 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];191 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
194 try bw.writeLeb128(export_flags);192 try leb.writeULEB128(writer, export_flags);
195 try bw.writeLeb128(vmaddr_offset);193 try leb.writeULEB128(writer, vmaddr_offset);
196 try bw.writeLeb128(bw.count);194 try leb.writeULEB128(writer, stream.bytes_written);
197 } else {195 } else {
198 node_size += 1; // 0x0 for non-terminal nodes196 node_size += 1; // 0x0 for non-terminal nodes
199 }197 }
...@@ -203,13 +201,13 @@ fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !Final...@@ -203,13 +201,13 @@ fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !Final
203 const edge = &self.edges.items[edge_index];201 const edge = &self.edges.items[edge_index];
204 const next_node_offset = slice.items(.trie_offset)[edge.node];202 const next_node_offset = slice.items(.trie_offset)[edge.node];
205 node_size += @intCast(edge.label.len + 1);203 node_size += @intCast(edge.label.len + 1);
206 try bw.writeLeb128(next_node_offset);204 try leb.writeULEB128(writer, next_node_offset);
207 }205 }
208206
209 const trie_offset = slice.items(.trie_offset)[node_index];207 const trie_offset = slice.items(.trie_offset)[node_index];
210 const updated = offset_in_trie != trie_offset;208 const updated = offset_in_trie != trie_offset;
211 slice.items(.trie_offset)[node_index] = offset_in_trie;209 slice.items(.trie_offset)[node_index] = offset_in_trie;
212 node_size += @intCast(bw.count);210 node_size += @intCast(stream.bytes_written);
213211
214 return .{ .node_size = node_size, .updated = updated };212 return .{ .node_size = node_size, .updated = updated };
215}213}
...@@ -225,11 +223,12 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {...@@ -225,11 +223,12 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {
225 }223 }
226 self.nodes.deinit(allocator);224 self.nodes.deinit(allocator);
227 self.edges.deinit(allocator);225 self.edges.deinit(allocator);
228 allocator.free(self.buffer);226 self.buffer.deinit(allocator);
229}227}
230228
231pub fn write(self: Trie, bw: *Writer) Writer.Error!void {229pub fn write(self: Trie, writer: anytype) !void {
232 try bw.writeAll(self.buffer);230 if (self.buffer.items.len == 0) return;
231 try writer.writeAll(self.buffer.items);
233}232}
234233
235/// Writes this node to a byte stream.234/// Writes this node to a byte stream.
...@@ -238,7 +237,7 @@ pub fn write(self: Trie, bw: *Writer) Writer.Error!void {...@@ -238,7 +237,7 @@ pub fn write(self: Trie, bw: *Writer) Writer.Error!void {
238/// iterate over `Trie.ordered_nodes` and call this method on each node.237/// iterate over `Trie.ordered_nodes` and call this method on each node.
239/// This is one of the requirements of the MachO.238/// This is one of the requirements of the MachO.
240/// Panics if `finalize` was not called before calling this method.239/// Panics if `finalize` was not called before calling this method.
241fn writeNode(self: *Trie, node_index: Node.Index, bw: *Writer) !void {240fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
242 const slice = self.nodes.slice();241 const slice = self.nodes.slice();
243 const edges = slice.items(.edges)[node_index];242 const edges = slice.items(.edges)[node_index];
244 const is_terminal = slice.items(.is_terminal)[node_index];243 const is_terminal = slice.items(.is_terminal)[node_index];
...@@ -246,28 +245,36 @@ fn writeNode(self: *Trie, node_index: Node.Index, bw: *Writer) !void {...@@ -246,28 +245,36 @@ fn writeNode(self: *Trie, node_index: Node.Index, bw: *Writer) !void {
246 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];245 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
247246
248 if (is_terminal) {247 if (is_terminal) {
249 const start = bw.count;248 // Terminal node info: encode export flags and vmaddr offset of this symbol.
249 var info_buf: [@sizeOf(u64) * 2]u8 = undefined;
250 var info_stream = std.io.fixedBufferStream(&info_buf);
250 // TODO Implement for special flags.251 // TODO Implement for special flags.
251 assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and252 assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
252 export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);253 export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
253 // Terminal node info: encode export flags and vmaddr offset of this symbol.254 try leb.writeULEB128(info_stream.writer(), export_flags);
254 try bw.writeLeb128(export_flags);255 try leb.writeULEB128(info_stream.writer(), vmaddr_offset);
255 try bw.writeLeb128(vmaddr_offset);256
256 // Encode the size of the terminal node info.257 // Encode the size of the terminal node info.
257 try bw.writeLeb128(bw.count - start);258 var size_buf: [@sizeOf(u64)]u8 = undefined;
259 var size_stream = std.io.fixedBufferStream(&size_buf);
260 try leb.writeULEB128(size_stream.writer(), info_stream.pos);
261
262 // Now, write them to the output stream.
263 try writer.writeAll(size_buf[0..size_stream.pos]);
264 try writer.writeAll(info_buf[0..info_stream.pos]);
258 } else {265 } else {
259 // Non-terminal node is delimited by 0 byte.266 // Non-terminal node is delimited by 0 byte.
260 try bw.writeByte(0);267 try writer.writeByte(0);
261 }268 }
262 // Write number of edges (max legal number of edges is 255).269 // Write number of edges (max legal number of edges is 256).
263 try bw.writeByte(@intCast(edges.items.len));270 try writer.writeByte(@as(u8, @intCast(edges.items.len)));
264271
265 for (edges.items) |edge_index| {272 for (edges.items) |edge_index| {
266 const edge = self.edges.items[edge_index];273 const edge = self.edges.items[edge_index];
267 // Write edge label and offset to next node in trie.274 // Write edge label and offset to next node in trie.
268 try bw.writeAll(edge.label);275 try writer.writeAll(edge.label);
269 try bw.writeByte(0);276 try writer.writeByte(0);
270 try bw.writeLeb128(slice.items(.trie_offset)[edge.node]);277 try leb.writeULEB128(writer, slice.items(.trie_offset)[edge.node]);
271 }278 }
272}279}
273280
...@@ -407,10 +414,8 @@ const macho = std.macho;...@@ -407,10 +414,8 @@ const macho = std.macho;
407const mem = std.mem;414const mem = std.mem;
408const std = @import("std");415const std = @import("std");
409const testing = std.testing;416const testing = std.testing;
410const Writer = std.io.Writer;
411
412const trace = @import("../../../tracy.zig").trace;417const trace = @import("../../../tracy.zig").trace;
413const DeprecatedLinearFifo = @import("../../../deprecated.zig").LinearFifo;418
414const Allocator = mem.Allocator;419const Allocator = mem.Allocator;
415const MachO = @import("../../MachO.zig");420const MachO = @import("../../MachO.zig");
416const Trie = @This();421const Trie = @This();
src/link/MachO/dyld_info/bind.zig+187-155
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1pub const Entry = struct {1pub const Entry = struct {
2 target: MachO.Ref,2 target: MachO.Ref,
3 offset: u64,3 offset: u64,
4 segment_id: u4,4 segment_id: u8,
5 addend: i64,5 addend: i64,
66
7 pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool {7 pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool {
...@@ -20,12 +20,14 @@ pub const Bind = struct {...@@ -20,12 +20,14 @@ pub const Bind = struct {
20 entries: std.ArrayListUnmanaged(Entry) = .empty,20 entries: std.ArrayListUnmanaged(Entry) = .empty,
21 buffer: std.ArrayListUnmanaged(u8) = .empty,21 buffer: std.ArrayListUnmanaged(u8) = .empty,
2222
23 pub fn deinit(bind: *Bind, gpa: Allocator) void {23 const Self = @This();
24 bind.entries.deinit(gpa);24
25 bind.buffer.deinit(gpa);25 pub fn deinit(self: *Self, gpa: Allocator) void {
26 self.entries.deinit(gpa);
27 self.buffer.deinit(gpa);
26 }28 }
2729
28 pub fn updateSize(bind: *Bind, macho_file: *MachO) !void {30 pub fn updateSize(self: *Self, macho_file: *MachO) !void {
29 const tracy = trace(@src());31 const tracy = trace(@src());
30 defer tracy.end();32 defer tracy.end();
3133
...@@ -54,12 +56,15 @@ pub const Bind = struct {...@@ -54,12 +56,15 @@ pub const Bind = struct {
54 const addend = rel.addend + rel.getRelocAddend(cpu_arch);56 const addend = rel.addend + rel.getRelocAddend(cpu_arch);
55 const sym = rel.getTargetSymbol(atom.*, macho_file);57 const sym = rel.getTargetSymbol(atom.*, macho_file);
56 if (sym.isTlvInit(macho_file)) continue;58 if (sym.isTlvInit(macho_file)) continue;
57 if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) (try bind.entries.addOne(gpa)).* = .{59 const entry = Entry{
58 .target = rel.getTargetSymbolRef(atom.*, macho_file),60 .target = rel.getTargetSymbolRef(atom.*, macho_file),
59 .offset = atom_addr + rel_offset - seg.vmaddr,61 .offset = atom_addr + rel_offset - seg.vmaddr,
60 .segment_id = seg_id,62 .segment_id = seg_id,
61 .addend = addend,63 .addend = addend,
62 };64 };
65 if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) {
66 try self.entries.append(gpa, entry);
67 }
63 }68 }
64 }69 }
65 }70 }
...@@ -70,12 +75,15 @@ pub const Bind = struct {...@@ -70,12 +75,15 @@ pub const Bind = struct {
70 for (macho_file.got.symbols.items, 0..) |ref, idx| {75 for (macho_file.got.symbols.items, 0..) |ref, idx| {
71 const sym = ref.getSymbol(macho_file).?;76 const sym = ref.getSymbol(macho_file).?;
72 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);77 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
73 if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{78 const entry = Entry{
74 .target = ref,79 .target = ref,
75 .offset = addr - seg.vmaddr,80 .offset = addr - seg.vmaddr,
76 .segment_id = seg_id,81 .segment_id = seg_id,
77 .addend = 0,82 .addend = 0,
78 };83 };
84 if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) {
85 try self.entries.append(gpa, entry);
86 }
79 }87 }
80 }88 }
8189
...@@ -86,12 +94,15 @@ pub const Bind = struct {...@@ -86,12 +94,15 @@ pub const Bind = struct {
86 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {94 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
87 const sym = ref.getSymbol(macho_file).?;95 const sym = ref.getSymbol(macho_file).?;
88 const addr = sect.addr + idx * @sizeOf(u64);96 const addr = sect.addr + idx * @sizeOf(u64);
89 if (sym.flags.import and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{97 const bind_entry = Entry{
90 .target = ref,98 .target = ref,
91 .offset = addr - seg.vmaddr,99 .offset = addr - seg.vmaddr,
92 .segment_id = seg_id,100 .segment_id = seg_id,
93 .addend = 0,101 .addend = 0,
94 };102 };
103 if (sym.flags.import and sym.flags.weak) {
104 try self.entries.append(gpa, bind_entry);
105 }
95 }106 }
96 }107 }
97108
...@@ -102,48 +113,49 @@ pub const Bind = struct {...@@ -102,48 +113,49 @@ pub const Bind = struct {
102 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {113 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
103 const sym = ref.getSymbol(macho_file).?;114 const sym = ref.getSymbol(macho_file).?;
104 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);115 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);
105 if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{116 const entry = Entry{
106 .target = ref,117 .target = ref,
107 .offset = addr - seg.vmaddr,118 .offset = addr - seg.vmaddr,
108 .segment_id = seg_id,119 .segment_id = seg_id,
109 .addend = 0,120 .addend = 0,
110 };121 };
122 if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) {
123 try self.entries.append(gpa, entry);
124 }
111 }125 }
112 }126 }
113127
114 try bind.finalize(gpa, macho_file);128 try self.finalize(gpa, macho_file);
115 macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));129 macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
116 }130 }
117131
118 fn finalize(bind: *Bind, gpa: Allocator, ctx: *MachO) !void {132 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
119 if (bind.entries.items.len == 0) return;133 if (self.entries.items.len == 0) return;
120134
121 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);135 const writer = self.buffer.writer(gpa);
122 const bw = &aw.writer;
123 defer bind.buffer = aw.toArrayList();
124136
125 log.debug("bind opcodes", .{});137 log.debug("bind opcodes", .{});
126138
127 std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan);139 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
128140
129 var start: usize = 0;141 var start: usize = 0;
130 var seg_id: ?u8 = null;142 var seg_id: ?u8 = null;
131 for (bind.entries.items, 0..) |entry, i| {143 for (self.entries.items, 0..) |entry, i| {
132 if (seg_id != null and seg_id.? == entry.segment_id) continue;144 if (seg_id != null and seg_id.? == entry.segment_id) continue;
133 try finalizeSegment(bind.entries.items[start..i], ctx, bw);145 try finalizeSegment(self.entries.items[start..i], ctx, writer);
134 seg_id = entry.segment_id;146 seg_id = entry.segment_id;
135 start = i;147 start = i;
136 }148 }
137149
138 try finalizeSegment(bind.entries.items[start..], ctx, bw);150 try finalizeSegment(self.entries.items[start..], ctx, writer);
139 try done(bw);151 try done(writer);
140 }152 }
141153
142 fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void {154 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {
143 if (entries.len == 0) return;155 if (entries.len == 0) return;
144156
145 const seg_id = entries[0].segment_id;157 const seg_id = entries[0].segment_id;
146 try setSegmentOffset(seg_id, 0, bw);158 try setSegmentOffset(seg_id, 0, writer);
147159
148 var offset: u64 = 0;160 var offset: u64 = 0;
149 var addend: i64 = 0;161 var addend: i64 = 0;
...@@ -163,15 +175,15 @@ pub const Bind = struct {...@@ -163,15 +175,15 @@ pub const Bind = struct {
163 if (target == null or !target.?.eql(current.target)) {175 if (target == null or !target.?.eql(current.target)) {
164 switch (state) {176 switch (state) {
165 .start => {},177 .start => {},
166 .bind_single => try doBind(bw),178 .bind_single => try doBind(writer),
167 .bind_times_skip => try doBindTimesSkip(count, skip, bw),179 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
168 }180 }
169 state = .start;181 state = .start;
170 target = current.target;182 target = current.target;
171183
172 const sym = current.target.getSymbol(ctx).?;184 const sym = current.target.getSymbol(ctx).?;
173 const name = sym.getName(ctx);185 const name = sym.getName(ctx);
174 const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;186 const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
175 const ordinal: i16 = ord: {187 const ordinal: i16 = ord: {
176 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;188 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
177 if (sym.flags.import) {189 if (sym.flags.import) {
...@@ -183,13 +195,13 @@ pub const Bind = struct {...@@ -183,13 +195,13 @@ pub const Bind = struct {
183 break :ord macho.BIND_SPECIAL_DYLIB_SELF;195 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
184 };196 };
185197
186 try setSymbol(name, flags, bw);198 try setSymbol(name, flags, writer);
187 try setTypePointer(bw);199 try setTypePointer(writer);
188 try setDylibOrdinal(ordinal, bw);200 try setDylibOrdinal(ordinal, writer);
189201
190 if (current.addend != addend) {202 if (current.addend != addend) {
191 addend = current.addend;203 addend = current.addend;
192 try setAddend(addend, bw);204 try setAddend(addend, writer);
193 }205 }
194 }206 }
195207
...@@ -198,11 +210,11 @@ pub const Bind = struct {...@@ -198,11 +210,11 @@ pub const Bind = struct {
198 switch (state) {210 switch (state) {
199 .start => {211 .start => {
200 if (current.offset < offset) {212 if (current.offset < offset) {
201 try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), bw);213 try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), writer);
202 offset = offset - (offset - current.offset);214 offset = offset - (offset - current.offset);
203 } else if (current.offset > offset) {215 } else if (current.offset > offset) {
204 const delta = current.offset - offset;216 const delta = current.offset - offset;
205 try addAddr(delta, bw);217 try addAddr(delta, writer);
206 offset += delta;218 offset += delta;
207 }219 }
208 state = .bind_single;220 state = .bind_single;
...@@ -211,7 +223,7 @@ pub const Bind = struct {...@@ -211,7 +223,7 @@ pub const Bind = struct {
211 },223 },
212 .bind_single => {224 .bind_single => {
213 if (current.offset == offset) {225 if (current.offset == offset) {
214 try doBind(bw);226 try doBind(writer);
215 state = .start;227 state = .start;
216 } else if (current.offset > offset) {228 } else if (current.offset > offset) {
217 const delta = current.offset - offset;229 const delta = current.offset - offset;
...@@ -225,9 +237,9 @@ pub const Bind = struct {...@@ -225,9 +237,9 @@ pub const Bind = struct {
225 if (current.offset < offset) {237 if (current.offset < offset) {
226 count -= 1;238 count -= 1;
227 if (count == 1) {239 if (count == 1) {
228 try doBindAddAddr(skip, bw);240 try doBindAddAddr(skip, writer);
229 } else {241 } else {
230 try doBindTimesSkip(count, skip, bw);242 try doBindTimesSkip(count, skip, writer);
231 }243 }
232 state = .start;244 state = .start;
233 offset = offset - (@sizeOf(u64) + skip);245 offset = offset - (@sizeOf(u64) + skip);
...@@ -236,7 +248,7 @@ pub const Bind = struct {...@@ -236,7 +248,7 @@ pub const Bind = struct {
236 count += 1;248 count += 1;
237 offset += @sizeOf(u64) + skip;249 offset += @sizeOf(u64) + skip;
238 } else {250 } else {
239 try doBindTimesSkip(count, skip, bw);251 try doBindTimesSkip(count, skip, writer);
240 state = .start;252 state = .start;
241 i -= 1;253 i -= 1;
242 }254 }
...@@ -246,13 +258,13 @@ pub const Bind = struct {...@@ -246,13 +258,13 @@ pub const Bind = struct {
246258
247 switch (state) {259 switch (state) {
248 .start => unreachable,260 .start => unreachable,
249 .bind_single => try doBind(bw),261 .bind_single => try doBind(writer),
250 .bind_times_skip => try doBindTimesSkip(count, skip, bw),262 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
251 }263 }
252 }264 }
253265
254 pub fn write(bind: Bind, bw: *Writer) Writer.Error!void {266 pub fn write(self: Self, writer: anytype) !void {
255 try bw.writeAll(bind.buffer.items);267 try writer.writeAll(self.buffer.items);
256 }268 }
257};269};
258270
...@@ -260,12 +272,14 @@ pub const WeakBind = struct {...@@ -260,12 +272,14 @@ pub const WeakBind = struct {
260 entries: std.ArrayListUnmanaged(Entry) = .empty,272 entries: std.ArrayListUnmanaged(Entry) = .empty,
261 buffer: std.ArrayListUnmanaged(u8) = .empty,273 buffer: std.ArrayListUnmanaged(u8) = .empty,
262274
263 pub fn deinit(bind: *WeakBind, gpa: Allocator) void {275 const Self = @This();
264 bind.entries.deinit(gpa);276
265 bind.buffer.deinit(gpa);277 pub fn deinit(self: *Self, gpa: Allocator) void {
278 self.entries.deinit(gpa);
279 self.buffer.deinit(gpa);
266 }280 }
267281
268 pub fn updateSize(bind: *WeakBind, macho_file: *MachO) !void {282 pub fn updateSize(self: *Self, macho_file: *MachO) !void {
269 const tracy = trace(@src());283 const tracy = trace(@src());
270 defer tracy.end();284 defer tracy.end();
271285
...@@ -294,12 +308,15 @@ pub const WeakBind = struct {...@@ -294,12 +308,15 @@ pub const WeakBind = struct {
294 const addend = rel.addend + rel.getRelocAddend(cpu_arch);308 const addend = rel.addend + rel.getRelocAddend(cpu_arch);
295 const sym = rel.getTargetSymbol(atom.*, macho_file);309 const sym = rel.getTargetSymbol(atom.*, macho_file);
296 if (sym.isTlvInit(macho_file)) continue;310 if (sym.isTlvInit(macho_file)) continue;
297 if (!sym.isLocal() and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{311 const entry = Entry{
298 .target = rel.getTargetSymbolRef(atom.*, macho_file),312 .target = rel.getTargetSymbolRef(atom.*, macho_file),
299 .offset = atom_addr + rel_offset - seg.vmaddr,313 .offset = atom_addr + rel_offset - seg.vmaddr,
300 .segment_id = seg_id,314 .segment_id = seg_id,
301 .addend = addend,315 .addend = addend,
302 };316 };
317 if (!sym.isLocal() and sym.flags.weak) {
318 try self.entries.append(gpa, entry);
319 }
303 }320 }
304 }321 }
305 }322 }
...@@ -310,12 +327,15 @@ pub const WeakBind = struct {...@@ -310,12 +327,15 @@ pub const WeakBind = struct {
310 for (macho_file.got.symbols.items, 0..) |ref, idx| {327 for (macho_file.got.symbols.items, 0..) |ref, idx| {
311 const sym = ref.getSymbol(macho_file).?;328 const sym = ref.getSymbol(macho_file).?;
312 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);329 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
313 if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{330 const entry = Entry{
314 .target = ref,331 .target = ref,
315 .offset = addr - seg.vmaddr,332 .offset = addr - seg.vmaddr,
316 .segment_id = seg_id,333 .segment_id = seg_id,
317 .addend = 0,334 .addend = 0,
318 };335 };
336 if (sym.flags.weak) {
337 try self.entries.append(gpa, entry);
338 }
319 }339 }
320 }340 }
321341
...@@ -327,12 +347,15 @@ pub const WeakBind = struct {...@@ -327,12 +347,15 @@ pub const WeakBind = struct {
327 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {347 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
328 const sym = ref.getSymbol(macho_file).?;348 const sym = ref.getSymbol(macho_file).?;
329 const addr = sect.addr + idx * @sizeOf(u64);349 const addr = sect.addr + idx * @sizeOf(u64);
330 if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{350 const bind_entry = Entry{
331 .target = ref,351 .target = ref,
332 .offset = addr - seg.vmaddr,352 .offset = addr - seg.vmaddr,
333 .segment_id = seg_id,353 .segment_id = seg_id,
334 .addend = 0,354 .addend = 0,
335 };355 };
356 if (sym.flags.weak) {
357 try self.entries.append(gpa, bind_entry);
358 }
336 }359 }
337 }360 }
338361
...@@ -343,48 +366,49 @@ pub const WeakBind = struct {...@@ -343,48 +366,49 @@ pub const WeakBind = struct {
343 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {366 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
344 const sym = ref.getSymbol(macho_file).?;367 const sym = ref.getSymbol(macho_file).?;
345 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);368 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);
346 if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{369 const entry = Entry{
347 .target = ref,370 .target = ref,
348 .offset = addr - seg.vmaddr,371 .offset = addr - seg.vmaddr,
349 .segment_id = seg_id,372 .segment_id = seg_id,
350 .addend = 0,373 .addend = 0,
351 };374 };
375 if (sym.flags.weak) {
376 try self.entries.append(gpa, entry);
377 }
352 }378 }
353 }379 }
354380
355 try bind.finalize(gpa, macho_file);381 try self.finalize(gpa, macho_file);
356 macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));382 macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
357 }383 }
358384
359 fn finalize(bind: *WeakBind, gpa: Allocator, ctx: *MachO) !void {385 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
360 if (bind.entries.items.len == 0) return;386 if (self.entries.items.len == 0) return;
361387
362 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);388 const writer = self.buffer.writer(gpa);
363 const bw = &aw.writer;
364 defer bind.buffer = aw.toArrayList();
365389
366 log.debug("weak bind opcodes", .{});390 log.debug("weak bind opcodes", .{});
367391
368 std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan);392 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
369393
370 var start: usize = 0;394 var start: usize = 0;
371 var seg_id: ?u8 = null;395 var seg_id: ?u8 = null;
372 for (bind.entries.items, 0..) |entry, i| {396 for (self.entries.items, 0..) |entry, i| {
373 if (seg_id != null and seg_id.? == entry.segment_id) continue;397 if (seg_id != null and seg_id.? == entry.segment_id) continue;
374 try finalizeSegment(bind.entries.items[start..i], ctx, bw);398 try finalizeSegment(self.entries.items[start..i], ctx, writer);
375 seg_id = entry.segment_id;399 seg_id = entry.segment_id;
376 start = i;400 start = i;
377 }401 }
378402
379 try finalizeSegment(bind.entries.items[start..], ctx, bw);403 try finalizeSegment(self.entries.items[start..], ctx, writer);
380 try done(bw);404 try done(writer);
381 }405 }
382406
383 fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void {407 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {
384 if (entries.len == 0) return;408 if (entries.len == 0) return;
385409
386 const seg_id = entries[0].segment_id;410 const seg_id = entries[0].segment_id;
387 try setSegmentOffset(seg_id, 0, bw);411 try setSegmentOffset(seg_id, 0, writer);
388412
389 var offset: u64 = 0;413 var offset: u64 = 0;
390 var addend: i64 = 0;414 var addend: i64 = 0;
...@@ -404,8 +428,8 @@ pub const WeakBind = struct {...@@ -404,8 +428,8 @@ pub const WeakBind = struct {
404 if (target == null or !target.?.eql(current.target)) {428 if (target == null or !target.?.eql(current.target)) {
405 switch (state) {429 switch (state) {
406 .start => {},430 .start => {},
407 .bind_single => try doBind(bw),431 .bind_single => try doBind(writer),
408 .bind_times_skip => try doBindTimesSkip(count, skip, bw),432 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
409 }433 }
410 state = .start;434 state = .start;
411 target = current.target;435 target = current.target;
...@@ -414,12 +438,12 @@ pub const WeakBind = struct {...@@ -414,12 +438,12 @@ pub const WeakBind = struct {
414 const name = sym.getName(ctx);438 const name = sym.getName(ctx);
415 const flags: u8 = 0; // TODO NON_WEAK_DEFINITION439 const flags: u8 = 0; // TODO NON_WEAK_DEFINITION
416440
417 try setSymbol(name, flags, bw);441 try setSymbol(name, flags, writer);
418 try setTypePointer(bw);442 try setTypePointer(writer);
419443
420 if (current.addend != addend) {444 if (current.addend != addend) {
421 addend = current.addend;445 addend = current.addend;
422 try setAddend(addend, bw);446 try setAddend(addend, writer);
423 }447 }
424 }448 }
425449
...@@ -428,11 +452,11 @@ pub const WeakBind = struct {...@@ -428,11 +452,11 @@ pub const WeakBind = struct {
428 switch (state) {452 switch (state) {
429 .start => {453 .start => {
430 if (current.offset < offset) {454 if (current.offset < offset) {
431 try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), bw);455 try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), writer);
432 offset = offset - (offset - current.offset);456 offset = offset - (offset - current.offset);
433 } else if (current.offset > offset) {457 } else if (current.offset > offset) {
434 const delta = current.offset - offset;458 const delta = current.offset - offset;
435 try addAddr(delta, bw);459 try addAddr(delta, writer);
436 offset += delta;460 offset += delta;
437 }461 }
438 state = .bind_single;462 state = .bind_single;
...@@ -441,7 +465,7 @@ pub const WeakBind = struct {...@@ -441,7 +465,7 @@ pub const WeakBind = struct {
441 },465 },
442 .bind_single => {466 .bind_single => {
443 if (current.offset == offset) {467 if (current.offset == offset) {
444 try doBind(bw);468 try doBind(writer);
445 state = .start;469 state = .start;
446 } else if (current.offset > offset) {470 } else if (current.offset > offset) {
447 const delta = current.offset - offset;471 const delta = current.offset - offset;
...@@ -455,9 +479,9 @@ pub const WeakBind = struct {...@@ -455,9 +479,9 @@ pub const WeakBind = struct {
455 if (current.offset < offset) {479 if (current.offset < offset) {
456 count -= 1;480 count -= 1;
457 if (count == 1) {481 if (count == 1) {
458 try doBindAddAddr(skip, bw);482 try doBindAddAddr(skip, writer);
459 } else {483 } else {
460 try doBindTimesSkip(count, skip, bw);484 try doBindTimesSkip(count, skip, writer);
461 }485 }
462 state = .start;486 state = .start;
463 offset = offset - (@sizeOf(u64) + skip);487 offset = offset - (@sizeOf(u64) + skip);
...@@ -466,7 +490,7 @@ pub const WeakBind = struct {...@@ -466,7 +490,7 @@ pub const WeakBind = struct {
466 count += 1;490 count += 1;
467 offset += @sizeOf(u64) + skip;491 offset += @sizeOf(u64) + skip;
468 } else {492 } else {
469 try doBindTimesSkip(count, skip, bw);493 try doBindTimesSkip(count, skip, writer);
470 state = .start;494 state = .start;
471 i -= 1;495 i -= 1;
472 }496 }
...@@ -476,13 +500,13 @@ pub const WeakBind = struct {...@@ -476,13 +500,13 @@ pub const WeakBind = struct {
476500
477 switch (state) {501 switch (state) {
478 .start => unreachable,502 .start => unreachable,
479 .bind_single => try doBind(bw),503 .bind_single => try doBind(writer),
480 .bind_times_skip => try doBindTimesSkip(count, skip, bw),504 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
481 }505 }
482 }506 }
483507
484 pub fn write(bind: WeakBind, bw: *Writer) Writer.Error!void {508 pub fn write(self: Self, writer: anytype) !void {
485 try bw.writeAll(bind.buffer.items);509 try writer.writeAll(self.buffer.items);
486 }510 }
487};511};
488512
...@@ -491,13 +515,15 @@ pub const LazyBind = struct {...@@ -491,13 +515,15 @@ pub const LazyBind = struct {
491 buffer: std.ArrayListUnmanaged(u8) = .empty,515 buffer: std.ArrayListUnmanaged(u8) = .empty,
492 offsets: std.ArrayListUnmanaged(u32) = .empty,516 offsets: std.ArrayListUnmanaged(u32) = .empty,
493517
494 pub fn deinit(bind: *LazyBind, gpa: Allocator) void {518 const Self = @This();
495 bind.entries.deinit(gpa);519
496 bind.buffer.deinit(gpa);520 pub fn deinit(self: *Self, gpa: Allocator) void {
497 bind.offsets.deinit(gpa);521 self.entries.deinit(gpa);
522 self.buffer.deinit(gpa);
523 self.offsets.deinit(gpa);
498 }524 }
499525
500 pub fn updateSize(bind: *LazyBind, macho_file: *MachO) !void {526 pub fn updateSize(self: *Self, macho_file: *MachO) !void {
501 const tracy = trace(@src());527 const tracy = trace(@src());
502 defer tracy.end();528 defer tracy.end();
503529
...@@ -511,35 +537,36 @@ pub const LazyBind = struct {...@@ -511,35 +537,36 @@ pub const LazyBind = struct {
511 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {537 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
512 const sym = ref.getSymbol(macho_file).?;538 const sym = ref.getSymbol(macho_file).?;
513 const addr = sect.addr + idx * @sizeOf(u64);539 const addr = sect.addr + idx * @sizeOf(u64);
514 if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{540 const bind_entry = Entry{
515 .target = ref,541 .target = ref,
516 .offset = addr - seg.vmaddr,542 .offset = addr - seg.vmaddr,
517 .segment_id = seg_id,543 .segment_id = seg_id,
518 .addend = 0,544 .addend = 0,
519 };545 };
546 if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) {
547 try self.entries.append(gpa, bind_entry);
548 }
520 }549 }
521550
522 try bind.finalize(gpa, macho_file);551 try self.finalize(gpa, macho_file);
523 macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));552 macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
524 }553 }
525554
526 fn finalize(bind: *LazyBind, gpa: Allocator, ctx: *MachO) !void {555 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
527 try bind.offsets.ensureTotalCapacityPrecise(gpa, bind.entries.items.len);556 try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);
528557
529 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);558 const writer = self.buffer.writer(gpa);
530 const bw = &aw.writer;
531 defer bind.buffer = aw.toArrayList();
532559
533 log.debug("lazy bind opcodes", .{});560 log.debug("lazy bind opcodes", .{});
534561
535 var addend: i64 = 0;562 var addend: i64 = 0;
536563
537 for (bind.entries.items) |entry| {564 for (self.entries.items) |entry| {
538 bind.offsets.appendAssumeCapacity(@intCast(bind.buffer.items.len));565 self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len));
539566
540 const sym = entry.target.getSymbol(ctx).?;567 const sym = entry.target.getSymbol(ctx).?;
541 const name = sym.getName(ctx);568 const name = sym.getName(ctx);
542 const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;569 const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
543 const ordinal: i16 = ord: {570 const ordinal: i16 = ord: {
544 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;571 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
545 if (sym.flags.import) {572 if (sym.flags.import) {
...@@ -551,116 +578,121 @@ pub const LazyBind = struct {...@@ -551,116 +578,121 @@ pub const LazyBind = struct {
551 break :ord macho.BIND_SPECIAL_DYLIB_SELF;578 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
552 };579 };
553580
554 try setSegmentOffset(entry.segment_id, entry.offset, bw);581 try setSegmentOffset(entry.segment_id, entry.offset, writer);
555 try setSymbol(name, flags, bw);582 try setSymbol(name, flags, writer);
556 try setDylibOrdinal(ordinal, bw);583 try setDylibOrdinal(ordinal, writer);
557584
558 if (entry.addend != addend) {585 if (entry.addend != addend) {
559 try setAddend(entry.addend, bw);586 try setAddend(entry.addend, writer);
560 addend = entry.addend;587 addend = entry.addend;
561 }588 }
562589
563 try doBind(bw);590 try doBind(writer);
564 try done(bw);591 try done(writer);
565 }592 }
566 }593 }
567594
568 pub fn write(bind: LazyBind, bw: *Writer) Writer.Error!void {595 pub fn write(self: Self, writer: anytype) !void {
569 try bw.writeAll(bind.buffer.items);596 try writer.writeAll(self.buffer.items);
570 }597 }
571};598};
572599
573fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {600fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
574 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });601 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
575 try bw.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segment_id);602 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
576 try bw.writeLeb128(offset);603 try std.leb.writeUleb128(writer, offset);
577}604}
578605
579fn setSymbol(name: []const u8, flags: u4, bw: *Writer) Writer.Error!void {606fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void {
580 log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });607 log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });
581 try bw.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags);608 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags)));
582 try bw.writeAll(name);609 try writer.writeAll(name);
583 try bw.writeByte(0);610 try writer.writeByte(0);
584}611}
585612
586fn setTypePointer(bw: *Writer) Writer.Error!void {613fn setTypePointer(writer: anytype) !void {
587 log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});614 log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});
588 try bw.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.BIND_TYPE_POINTER)));615 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER)));
589}616}
590617
591fn setDylibOrdinal(ordinal: i16, bw: *Writer) Writer.Error!void {618fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {
592 switch (ordinal) {619 if (ordinal <= 0) {
593 else => unreachable, // Invalid dylib special binding620 switch (ordinal) {
594 macho.BIND_SPECIAL_DYLIB_SELF,621 macho.BIND_SPECIAL_DYLIB_SELF,
595 macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE,622 macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE,
596 macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP,623 macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP,
597 => {624 => {},
598 log.debug(">>> set dylib special: {d}", .{ordinal});625 else => unreachable, // Invalid dylib special binding
599 try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @bitCast(@as(i4, @intCast(ordinal)))));626 }
600 },627 log.debug(">>> set dylib special: {d}", .{ordinal});
601 1...std.math.maxInt(i16) => {628 const cast = @as(u16, @bitCast(ordinal));
602 log.debug(">>> set dylib ordinal: {d}", .{ordinal});629 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @truncate(cast)));
603 if (std.math.cast(u4, ordinal)) |imm| {630 } else {
604 try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | imm);631 const cast = @as(u16, @bitCast(ordinal));
605 } else {632 log.debug(">>> set dylib ordinal: {d}", .{ordinal});
606 try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);633 if (cast <= 0xf) {
607 try bw.writeUleb128(ordinal);634 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @as(u4, @truncate(cast)));
608 }635 } else {
609 },636 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
637 try std.leb.writeUleb128(writer, cast);
638 }
610 }639 }
611}640}
612641
613fn setAddend(addend: i64, bw: *Writer) Writer.Error!void {642fn setAddend(addend: i64, writer: anytype) !void {
614 log.debug(">>> set addend: {x}", .{addend});643 log.debug(">>> set addend: {x}", .{addend});
615 try bw.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);644 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
616 try bw.writeLeb128(addend);645 try std.leb.writeIleb128(writer, addend);
617}646}
618647
619fn doBind(bw: *Writer) Writer.Error!void {648fn doBind(writer: anytype) !void {
620 log.debug(">>> bind", .{});649 log.debug(">>> bind", .{});
621 try bw.writeByte(macho.BIND_OPCODE_DO_BIND);650 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
622}651}
623652
624fn doBindAddAddr(addr: u64, bw: *Writer) Writer.Error!void {653fn doBindAddAddr(addr: u64, writer: anytype) !void {
625 log.debug(">>> bind with add: {x}", .{addr});654 log.debug(">>> bind with add: {x}", .{addr});
626 if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| {655 if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {
627 if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte(656 const imm = @divExact(addr, @sizeOf(u64));
628 macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | imm_scaled,657 if (imm <= 0xf) {
629 );658 try writer.writeByte(
630 } else |_| {}659 macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)),
631 try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);660 );
632 try bw.writeLeb128(addr);661 return;
662 }
663 }
664 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
665 try std.leb.writeUleb128(writer, addr);
633}666}
634667
635fn doBindTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {668fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void {
636 log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });669 log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });
637 try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);670 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
638 try bw.writeLeb128(count);671 try std.leb.writeUleb128(writer, count);
639 try bw.writeLeb128(skip);672 try std.leb.writeUleb128(writer, skip);
640}673}
641674
642fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {675fn addAddr(addr: u64, writer: anytype) !void {
643 log.debug(">>> add: {x}", .{addr});676 log.debug(">>> add: {x}", .{addr});
644 try bw.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);677 try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
645 try bw.writeLeb128(addr);678 try std.leb.writeUleb128(writer, addr);
646}679}
647680
648fn done(bw: *Writer) Writer.Error!void {681fn done(writer: anytype) !void {
649 log.debug(">>> done", .{});682 log.debug(">>> done", .{});
650 try bw.writeByte(macho.BIND_OPCODE_DONE);683 try writer.writeByte(macho.BIND_OPCODE_DONE);
651}684}
652685
653const std = @import("std");
654const assert = std.debug.assert;686const assert = std.debug.assert;
655const leb = std.leb;687const leb = std.leb;
656const log = std.log.scoped(.link_dyld_info);688const log = std.log.scoped(.link_dyld_info);
657const macho = std.macho;689const macho = std.macho;
658const mem = std.mem;690const mem = std.mem;
659const testing = std.testing;691const testing = std.testing;
660const Allocator = std.mem.Allocator;
661const Writer = std.io.Writer;
662
663const trace = @import("../../../tracy.zig").trace;692const trace = @import("../../../tracy.zig").trace;
693const std = @import("std");
694
695const Allocator = mem.Allocator;
664const File = @import("../file.zig").File;696const File = @import("../file.zig").File;
665const MachO = @import("../../MachO.zig");697const MachO = @import("../../MachO.zig");
666const Symbol = @import("../Symbol.zig");698const Symbol = @import("../Symbol.zig");
src/link/MachO/eh_frame.zig+69-44
...@@ -12,33 +12,36 @@ pub const Cie = struct {...@@ -12,33 +12,36 @@ pub const Cie = struct {
12 const tracy = trace(@src());12 const tracy = trace(@src());
13 defer tracy.end();13 defer tracy.end();
1414
15 var r: std.io.Reader = .fixed(cie.getData(macho_file));15 const data = cie.getData(macho_file);
16 const aug = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(data.ptr + 9)), 0);
1617
17 try r.discard(9);
18 const aug = try r.takeSentinel(0);
19 if (aug[0] != 'z') return; // TODO should we error out?18 if (aug[0] != 'z') return; // TODO should we error out?
2019
21 _ = try r.takeLeb128(u64); // code alignment factor20 var stream = std.io.fixedBufferStream(data[9 + aug.len + 1 ..]);
22 _ = try r.takeLeb128(u64); // data alignment factor21 var creader = std.io.countingReader(stream.reader());
23 _ = try r.takeLeb128(u64); // return address register22 const reader = creader.reader();
24 _ = try r.takeLeb128(u64); // augmentation data length23
24 _ = try leb.readUleb128(u64, reader); // code alignment factor
25 _ = try leb.readUleb128(u64, reader); // data alignment factor
26 _ = try leb.readUleb128(u64, reader); // return address register
27 _ = try leb.readUleb128(u64, reader); // augmentation data length
2528
26 for (aug[1..]) |ch| switch (ch) {29 for (aug[1..]) |ch| switch (ch) {
27 'R' => {30 'R' => {
28 const enc = try r.takeByte();31 const enc = try reader.readByte();
29 if (enc != DW_EH_PE.pcrel | DW_EH_PE.absptr) {32 if (enc != DW_EH_PE.pcrel | DW_EH_PE.absptr) {
30 @panic("unexpected pointer encoding"); // TODO error33 @panic("unexpected pointer encoding"); // TODO error
31 }34 }
32 },35 },
33 'P' => {36 'P' => {
34 const enc = try r.takeByte();37 const enc = try reader.readByte();
35 if (enc != DW_EH_PE.pcrel | DW_EH_PE.indirect | DW_EH_PE.sdata4) {38 if (enc != DW_EH_PE.pcrel | DW_EH_PE.indirect | DW_EH_PE.sdata4) {
36 @panic("unexpected personality pointer encoding"); // TODO error39 @panic("unexpected personality pointer encoding"); // TODO error
37 }40 }
38 _ = try r.takeInt(u32, .little); // personality pointer41 _ = try reader.readInt(u32, .little); // personality pointer
39 },42 },
40 'L' => {43 'L' => {
41 const enc = try r.takeByte();44 const enc = try reader.readByte();
42 switch (enc & DW_EH_PE.type_mask) {45 switch (enc & DW_EH_PE.type_mask) {
43 DW_EH_PE.sdata4 => cie.lsda_size = .p32,46 DW_EH_PE.sdata4 => cie.lsda_size = .p32,
44 DW_EH_PE.absptr => cie.lsda_size = .p64,47 DW_EH_PE.absptr => cie.lsda_size = .p64,
...@@ -125,16 +128,12 @@ pub const Fde = struct {...@@ -125,16 +128,12 @@ pub const Fde = struct {
125 const tracy = trace(@src());128 const tracy = trace(@src());
126 defer tracy.end();129 defer tracy.end();
127130
131 const data = fde.getData(macho_file);
128 const object = fde.getObject(macho_file);132 const object = fde.getObject(macho_file);
129 const sect = object.sections.items(.header)[object.eh_frame_sect_index.?];133 const sect = object.sections.items(.header)[object.eh_frame_sect_index.?];
130134
131 var br: std.io.Reader = .fixed(fde.getData(macho_file));
132
133 try br.discard(4);
134 const cie_ptr = try br.takeInt(u32, .little);
135 const pc_begin = try br.takeInt(i64, .little);
136
137 // Parse target atom index135 // Parse target atom index
136 const pc_begin = std.mem.readInt(i64, data[8..][0..8], .little);
138 const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);137 const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
139 fde.atom = object.findAtom(taddr) orelse {138 fde.atom = object.findAtom(taddr) orelse {
140 try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{139 try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
...@@ -146,6 +145,7 @@ pub const Fde = struct {...@@ -146,6 +145,7 @@ pub const Fde = struct {
146 fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));145 fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
147146
148 // Associate with a CIE147 // Associate with a CIE
148 const cie_ptr = std.mem.readInt(u32, data[4..8], .little);
149 const cie_offset = fde.offset + 4 - cie_ptr;149 const cie_offset = fde.offset + 4 - cie_ptr;
150 const cie_index = for (object.cies.items, 0..) |cie, cie_index| {150 const cie_index = for (object.cies.items, 0..) |cie, cie_index| {
151 if (cie.offset == cie_offset) break @as(Cie.Index, @intCast(cie_index));151 if (cie.offset == cie_offset) break @as(Cie.Index, @intCast(cie_index));
...@@ -163,12 +163,14 @@ pub const Fde = struct {...@@ -163,12 +163,14 @@ pub const Fde = struct {
163163
164 // Parse LSDA atom index if any164 // Parse LSDA atom index if any
165 if (cie.lsda_size) |lsda_size| {165 if (cie.lsda_size) |lsda_size| {
166 try br.discard(8);166 var stream = std.io.fixedBufferStream(data[24..]);
167 _ = try br.takeLeb128(u64); // augmentation length167 var creader = std.io.countingReader(stream.reader());
168 fde.lsda_ptr_offset = @intCast(br.seek);168 const reader = creader.reader();
169 _ = try leb.readUleb128(u64, reader); // augmentation length
170 fde.lsda_ptr_offset = @intCast(creader.bytes_read + 24);
169 const lsda_ptr = switch (lsda_size) {171 const lsda_ptr = switch (lsda_size) {
170 .p32 => try br.takeInt(i32, .little),172 .p32 => try reader.readInt(i32, .little),
171 .p64 => try br.takeInt(i64, .little),173 .p64 => try reader.readInt(i64, .little),
172 };174 };
173 const lsda_addr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + fde.lsda_ptr_offset)) + lsda_ptr);175 const lsda_addr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + fde.lsda_ptr_offset)) + lsda_ptr);
174 fde.lsda = object.findAtom(lsda_addr) orelse {176 fde.lsda = object.findAtom(lsda_addr) orelse {
...@@ -209,35 +211,56 @@ pub const Fde = struct {...@@ -209,35 +211,56 @@ pub const Fde = struct {
209 return fde.getObject(macho_file).getAtom(fde.lsda);211 return fde.getObject(macho_file).getAtom(fde.lsda);
210 }212 }
211213
212 pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {214 pub fn format(
215 fde: Fde,
216 comptime unused_fmt_string: []const u8,
217 options: std.fmt.FormatOptions,
218 writer: anytype,
219 ) !void {
220 _ = fde;
221 _ = unused_fmt_string;
222 _ = options;
223 _ = writer;
224 @compileError("do not format FDEs directly");
225 }
226
227 pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(format2) {
213 return .{ .data = .{228 return .{ .data = .{
214 .fde = fde,229 .fde = fde,
215 .macho_file = macho_file,230 .macho_file = macho_file,
216 } };231 } };
217 }232 }
218233
219 const Format = struct {234 const FormatContext = struct {
220 fde: Fde,235 fde: Fde,
221 macho_file: *MachO,236 macho_file: *MachO,
222
223 fn default(f: Format, w: *Writer) Writer.Error!void {
224 const fde = f.fde;
225 const macho_file = f.macho_file;
226 try w.print("@{x} : size({x}) : cie({d}) : {s}", .{
227 fde.offset,
228 fde.getSize(),
229 fde.cie,
230 fde.getAtom(macho_file).getName(macho_file),
231 });
232 if (!fde.alive) try w.writeAll(" : [*]");
233 }
234 };237 };
235238
239 fn format2(
240 ctx: FormatContext,
241 comptime unused_fmt_string: []const u8,
242 options: std.fmt.FormatOptions,
243 writer: anytype,
244 ) !void {
245 _ = unused_fmt_string;
246 _ = options;
247 const fde = ctx.fde;
248 const macho_file = ctx.macho_file;
249 try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
250 fde.offset,
251 fde.getSize(),
252 fde.cie,
253 fde.getAtom(macho_file).getName(macho_file),
254 });
255 if (!fde.alive) try writer.writeAll(" : [*]");
256 }
257
236 pub const Index = u32;258 pub const Index = u32;
237};259};
238260
239pub const Iterator = struct {261pub const Iterator = struct {
240 reader: *std.io.Reader,262 data: []const u8,
263 pos: u32 = 0,
241264
242 pub const Record = struct {265 pub const Record = struct {
243 tag: enum { fde, cie },266 tag: enum { fde, cie },
...@@ -246,19 +269,21 @@ pub const Iterator = struct {...@@ -246,19 +269,21 @@ pub const Iterator = struct {
246 };269 };
247270
248 pub fn next(it: *Iterator) !?Record {271 pub fn next(it: *Iterator) !?Record {
249 const r = it.reader;272 if (it.pos >= it.data.len) return null;
250 if (r.seek >= r.storageBuffer().len) return null;273
274 var stream = std.io.fixedBufferStream(it.data[it.pos..]);
275 const reader = stream.reader();
251276
252 const size = try r.takeInt(u32, .little);277 const size = try reader.readInt(u32, .little);
253 if (size == 0xFFFFFFFF) @panic("DWARF CFI is 32bit on macOS");278 if (size == 0xFFFFFFFF) @panic("DWARF CFI is 32bit on macOS");
254279
255 const id = try r.takeInt(u32, .little);280 const id = try reader.readInt(u32, .little);
256 const record: Record = .{281 const record = Record{
257 .tag = if (id == 0) .cie else .fde,282 .tag = if (id == 0) .cie else .fde,
258 .offset = @intCast(r.seek),283 .offset = it.pos,
259 .size = size,284 .size = size,
260 };285 };
261 try r.discard(size);286 it.pos += size + 4;
262287
263 return record;288 return record;
264 }289 }
src/link/MachO/file.zig+3-3
...@@ -321,11 +321,11 @@ pub const File = union(enum) {...@@ -321,11 +321,11 @@ pub const File = union(enum) {
321 };321 };
322 }322 }
323323
324 pub fn writeAr(file: File, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) Writer.Error!void {324 pub fn writeAr(file: File, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
325 return switch (file) {325 return switch (file) {
326 .dylib, .internal => unreachable,326 .dylib, .internal => unreachable,
327 .zig_object => |x| x.writeAr(bw, ar_format),327 .zig_object => |x| x.writeAr(ar_format, writer),
328 .object => |x| x.writeAr(bw, ar_format, macho_file),328 .object => |x| x.writeAr(ar_format, macho_file, writer),
329 };329 };
330 }330 }
331331
src/link/MachO/load_commands.zig+30-21
...@@ -181,20 +181,23 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {...@@ -181,20 +181,23 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
181 return offset;181 return offset;
182}182}
183183
184pub fn writeDylinkerLC(bw: *Writer) Writer.Error!void {184pub fn writeDylinkerLC(writer: anytype) !void {
185 const name_len = mem.sliceTo(default_dyld_path, 0).len;185 const name_len = mem.sliceTo(default_dyld_path, 0).len;
186 const cmdsize = @as(u32, @intCast(mem.alignForward(186 const cmdsize = @as(u32, @intCast(mem.alignForward(
187 u64,187 u64,
188 @sizeOf(macho.dylinker_command) + name_len,188 @sizeOf(macho.dylinker_command) + name_len,
189 @sizeOf(u64),189 @sizeOf(u64),
190 )));190 )));
191 try bw.writeStruct(macho.dylinker_command{191 try writer.writeStruct(macho.dylinker_command{
192 .cmd = .LOAD_DYLINKER,192 .cmd = .LOAD_DYLINKER,
193 .cmdsize = cmdsize,193 .cmdsize = cmdsize,
194 .name = @sizeOf(macho.dylinker_command),194 .name = @sizeOf(macho.dylinker_command),
195 });195 });
196 try bw.writeAll(mem.sliceTo(default_dyld_path, 0));196 try writer.writeAll(mem.sliceTo(default_dyld_path, 0));
197 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylinker_command) - name_len);197 const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;
198 if (padding > 0) {
199 try writer.writeByteNTimes(0, padding);
200 }
198}201}
199202
200const WriteDylibLCCtx = struct {203const WriteDylibLCCtx = struct {
...@@ -205,14 +208,14 @@ const WriteDylibLCCtx = struct {...@@ -205,14 +208,14 @@ const WriteDylibLCCtx = struct {
205 compatibility_version: u32 = 0x10000,208 compatibility_version: u32 = 0x10000,
206};209};
207210
208pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {211pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
209 const name_len = ctx.name.len + 1;212 const name_len = ctx.name.len + 1;
210 const cmdsize: u32 = @intCast(mem.alignForward(213 const cmdsize = @as(u32, @intCast(mem.alignForward(
211 u64,214 u64,
212 @sizeOf(macho.dylib_command) + name_len,215 @sizeOf(macho.dylib_command) + name_len,
213 @sizeOf(u64),216 @sizeOf(u64),
214 ));217 )));
215 try bw.writeStruct(macho.dylib_command{218 try writer.writeStruct(macho.dylib_command{
216 .cmd = ctx.cmd,219 .cmd = ctx.cmd,
217 .cmdsize = cmdsize,220 .cmdsize = cmdsize,
218 .dylib = .{221 .dylib = .{
...@@ -222,9 +225,12 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {...@@ -222,9 +225,12 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {
222 .compatibility_version = ctx.compatibility_version,225 .compatibility_version = ctx.compatibility_version,
223 },226 },
224 });227 });
225 try bw.writeAll(ctx.name);228 try writer.writeAll(ctx.name);
226 try bw.writeByte(0);229 try writer.writeByte(0);
227 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylib_command) - name_len);230 const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;
231 if (padding > 0) {
232 try writer.writeByteNTimes(0, padding);
233 }
228}234}
229235
230pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {236pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
...@@ -253,23 +259,26 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {...@@ -253,23 +259,26 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
253 }, writer);259 }, writer);
254}260}
255261
256pub fn writeRpathLC(bw: *Writer, rpath: []const u8) !void {262pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {
257 const rpath_len = rpath.len + 1;263 const rpath_len = rpath.len + 1;
258 const cmdsize = @as(u32, @intCast(mem.alignForward(264 const cmdsize = @as(u32, @intCast(mem.alignForward(
259 u64,265 u64,
260 @sizeOf(macho.rpath_command) + rpath_len,266 @sizeOf(macho.rpath_command) + rpath_len,
261 @sizeOf(u64),267 @sizeOf(u64),
262 )));268 )));
263 try bw.writeStruct(macho.rpath_command{269 try writer.writeStruct(macho.rpath_command{
264 .cmdsize = cmdsize,270 .cmdsize = cmdsize,
265 .path = @sizeOf(macho.rpath_command),271 .path = @sizeOf(macho.rpath_command),
266 });272 });
267 try bw.writeAll(rpath);273 try writer.writeAll(rpath);
268 try bw.writeByte(0);274 try writer.writeByte(0);
269 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.rpath_command) - rpath_len);275 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
276 if (padding > 0) {
277 try writer.writeByteNTimes(0, padding);
278 }
270}279}
271280
272pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) Writer.Error!void {281pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {
273 const cmd: macho.LC = switch (platform.os_tag) {282 const cmd: macho.LC = switch (platform.os_tag) {
274 .macos => .VERSION_MIN_MACOSX,283 .macos => .VERSION_MIN_MACOSX,
275 .ios => .VERSION_MIN_IPHONEOS,284 .ios => .VERSION_MIN_IPHONEOS,
...@@ -277,7 +286,7 @@ pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?st...@@ -277,7 +286,7 @@ pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?st
277 .watchos => .VERSION_MIN_WATCHOS,286 .watchos => .VERSION_MIN_WATCHOS,
278 else => unreachable,287 else => unreachable,
279 };288 };
280 try bw.writeAll(mem.asBytes(&macho.version_min_command{289 try writer.writeAll(mem.asBytes(&macho.version_min_command{
281 .cmd = cmd,290 .cmd = cmd,
282 .version = platform.toAppleVersion(),291 .version = platform.toAppleVersion(),
283 .sdk = if (sdk_version) |ver|292 .sdk = if (sdk_version) |ver|
...@@ -287,9 +296,9 @@ pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?st...@@ -287,9 +296,9 @@ pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?st
287 }));296 }));
288}297}
289298
290pub fn writeBuildVersionLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) Writer.Error!void {299pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {
291 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);300 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
292 try bw.writeStruct(macho.build_version_command{301 try writer.writeStruct(macho.build_version_command{
293 .cmdsize = cmdsize,302 .cmdsize = cmdsize,
294 .platform = platform.toApplePlatform(),303 .platform = platform.toApplePlatform(),
295 .minos = platform.toAppleVersion(),304 .minos = platform.toAppleVersion(),
...@@ -299,7 +308,7 @@ pub fn writeBuildVersionLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?...@@ -299,7 +308,7 @@ pub fn writeBuildVersionLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?
299 platform.toAppleVersion(),308 platform.toAppleVersion(),
300 .ntools = 1,309 .ntools = 1,
301 });310 });
302 try bw.writeAll(mem.asBytes(&macho.build_tool_version{311 try writer.writeAll(mem.asBytes(&macho.build_tool_version{
303 .tool = .ZIG,312 .tool = .ZIG,
304 .version = 0x0,313 .version = 0x0,
305 }));314 }));
src/link/MachO/relocatable.zig+52-24
...@@ -202,30 +202,38 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -202,30 +202,38 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
202 };202 };
203203
204 if (build_options.enable_logging) {204 if (build_options.enable_logging) {
205 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});205 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(macho_file)});
206 }206 }
207207
208 var bw: Writer = .fixed(try gpa.alloc(u8, total_size));208 var buffer = std.ArrayList(u8).init(gpa);
209 defer gpa.free(bw.buffer);209 defer buffer.deinit();
210 try buffer.ensureTotalCapacityPrecise(total_size);
211 const writer = buffer.writer();
210212
211 // Write magic213 // Write magic
212 bw.writeAll(Archive.ARMAG) catch unreachable;214 try writer.writeAll(Archive.ARMAG);
213215
214 // Write symtab216 // Write symtab
215 ar_symtab.write(&bw, format, macho_file) catch |err| {217 ar_symtab.write(format, macho_file, writer) catch |err| switch (err) {
216 return diags.fail("failed to write archive symbol table: {s}", .{@errorName(err)});218 error.OutOfMemory => return error.OutOfMemory,
219 else => |e| return diags.fail("failed to write archive symbol table: {s}", .{@errorName(e)}),
217 };220 };
218221
219 // Write object files222 // Write object files
220 for (files.items) |index| {223 for (files.items) |index| {
221 bw.splatByteAll(0, mem.alignForward(usize, bw.end, 2) - bw.end) catch unreachable;224 const aligned = mem.alignForward(usize, buffer.items.len, 2);
222 macho_file.getFile(index).?.writeAr(&bw, format, macho_file) catch |err|225 const padding = aligned - buffer.items.len;
226 if (padding > 0) {
227 try writer.writeByteNTimes(0, padding);
228 }
229 macho_file.getFile(index).?.writeAr(format, macho_file, writer) catch |err|
223 return diags.fail("failed to write archive: {s}", .{@errorName(err)});230 return diags.fail("failed to write archive: {s}", .{@errorName(err)});
224 }231 }
225232
226 assert(bw.end == bw.buffer.len);233 assert(buffer.items.len == total_size);
227 try macho_file.setEndPos(bw.end);234
228 try macho_file.pwriteAll(bw.buffer, 0);235 try macho_file.setEndPos(total_size);
236 try macho_file.pwriteAll(buffer.items, 0);
229237
230 if (diags.hasErrors()) return error.LinkFailure;238 if (diags.hasErrors()) return error.LinkFailure;
231}239}
...@@ -664,7 +672,7 @@ fn writeCompactUnwindWorker(macho_file: *MachO, object: *Object) void {...@@ -664,7 +672,7 @@ fn writeCompactUnwindWorker(macho_file: *MachO, object: *Object) void {
664 diags.addError("failed to write '__LD,__eh_frame' section: {s}", .{@errorName(err)});672 diags.addError("failed to write '__LD,__eh_frame' section: {s}", .{@errorName(err)});
665}673}
666674
667fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {675fn writeSectionsToFile(macho_file: *MachO) !void {
668 const tracy = trace(@src());676 const tracy = trace(@src());
669 defer tracy.end();677 defer tracy.end();
670678
...@@ -681,8 +689,12 @@ fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {...@@ -681,8 +689,12 @@ fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {
681689
682fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } {690fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } {
683 const gpa = macho_file.base.comp.gpa;691 const gpa = macho_file.base.comp.gpa;
684 var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeObject(macho_file)));692 const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file);
685 defer gpa.free(bw.buffer);693 const buffer = try gpa.alloc(u8, needed_size);
694 defer gpa.free(buffer);
695
696 var stream = std.io.fixedBufferStream(buffer);
697 const writer = stream.writer();
686698
687 var ncmds: usize = 0;699 var ncmds: usize = 0;
688700
...@@ -690,31 +702,47 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc...@@ -690,31 +702,47 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
690 {702 {
691 assert(macho_file.segments.items.len == 1);703 assert(macho_file.segments.items.len == 1);
692 const seg = macho_file.segments.items[0];704 const seg = macho_file.segments.items[0];
693 bw.writeStruct(seg) catch unreachable;705 writer.writeStruct(seg) catch |err| switch (err) {
706 error.NoSpaceLeft => unreachable,
707 };
694 for (macho_file.sections.items(.header)) |header| {708 for (macho_file.sections.items(.header)) |header| {
695 bw.writeStruct(header) catch unreachable;709 writer.writeStruct(header) catch |err| switch (err) {
710 error.NoSpaceLeft => unreachable,
711 };
696 }712 }
697 ncmds += 1;713 ncmds += 1;
698 }714 }
699715
700 bw.writeStruct(macho_file.data_in_code_cmd) catch unreachable;716 writer.writeStruct(macho_file.data_in_code_cmd) catch |err| switch (err) {
717 error.NoSpaceLeft => unreachable,
718 };
701 ncmds += 1;719 ncmds += 1;
702 bw.writeStruct(macho_file.symtab_cmd) catch unreachable;720 writer.writeStruct(macho_file.symtab_cmd) catch |err| switch (err) {
721 error.NoSpaceLeft => unreachable,
722 };
703 ncmds += 1;723 ncmds += 1;
704 bw.writeStruct(macho_file.dysymtab_cmd) catch unreachable;724 writer.writeStruct(macho_file.dysymtab_cmd) catch |err| switch (err) {
725 error.NoSpaceLeft => unreachable,
726 };
705 ncmds += 1;727 ncmds += 1;
706728
707 if (macho_file.platform.isBuildVersionCompatible()) {729 if (macho_file.platform.isBuildVersionCompatible()) {
708 load_commands.writeBuildVersionLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable;730 load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
731 error.NoSpaceLeft => unreachable,
732 };
709 ncmds += 1;733 ncmds += 1;
710 } else {734 } else {
711 load_commands.writeVersionMinLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable;735 load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
736 error.NoSpaceLeft => unreachable,
737 };
712 ncmds += 1;738 ncmds += 1;
713 }739 }
714740
715 assert(bw.end == bw.buffer.len);741 assert(stream.pos == needed_size);
716 try macho_file.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));742
717 return .{ ncmds, bw.end };743 try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
744
745 return .{ ncmds, buffer.len };
718}746}
719747
720fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {748fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
src/link/MachO/synthetic.zig+54-54
...@@ -27,13 +27,13 @@ pub const GotSection = struct {...@@ -27,13 +27,13 @@ pub const GotSection = struct {
27 return got.symbols.items.len * @sizeOf(u64);27 return got.symbols.items.len * @sizeOf(u64);
28 }28 }
2929
30 pub fn write(got: GotSection, macho_file: *MachO, bw: *Writer) !void {30 pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void {
31 const tracy = trace(@src());31 const tracy = trace(@src());
32 defer tracy.end();32 defer tracy.end();
33 for (got.symbols.items) |ref| {33 for (got.symbols.items) |ref| {
34 const sym = ref.getSymbol(macho_file).?;34 const sym = ref.getSymbol(macho_file).?;
35 const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file);35 const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file);
36 try bw.writeInt(u64, value, .little);36 try writer.writeInt(u64, value, .little);
37 }37 }
38 }38 }
3939
...@@ -89,7 +89,7 @@ pub const StubsSection = struct {...@@ -89,7 +89,7 @@ pub const StubsSection = struct {
89 return stubs.symbols.items.len * header.reserved2;89 return stubs.symbols.items.len * header.reserved2;
90 }90 }
9191
92 pub fn write(stubs: StubsSection, macho_file: *MachO, bw: *Writer) !void {92 pub fn write(stubs: StubsSection, macho_file: *MachO, writer: anytype) !void {
93 const tracy = trace(@src());93 const tracy = trace(@src());
94 defer tracy.end();94 defer tracy.end();
95 const cpu_arch = macho_file.getTarget().cpu.arch;95 const cpu_arch = macho_file.getTarget().cpu.arch;
...@@ -101,20 +101,20 @@ pub const StubsSection = struct {...@@ -101,20 +101,20 @@ pub const StubsSection = struct {
101 const target = laptr_sect.addr + idx * @sizeOf(u64);101 const target = laptr_sect.addr + idx * @sizeOf(u64);
102 switch (cpu_arch) {102 switch (cpu_arch) {
103 .x86_64 => {103 .x86_64 => {
104 try bw.writeAll(&.{ 0xff, 0x25 });104 try writer.writeAll(&.{ 0xff, 0x25 });
105 try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little);105 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
106 },106 },
107 .aarch64 => {107 .aarch64 => {
108 // TODO relax if possible108 // TODO relax if possible
109 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));109 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
110 try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);110 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
111 const off = try math.divExact(u12, @truncate(target), 8);111 const off = try math.divExact(u12, @truncate(target), 8);
112 try bw.writeInt(112 try writer.writeInt(
113 u32,113 u32,
114 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),114 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
115 .little,115 .little,
116 );116 );
117 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);117 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
118 },118 },
119 else => unreachable,119 else => unreachable,
120 }120 }
...@@ -175,11 +175,11 @@ pub const StubsHelperSection = struct {...@@ -175,11 +175,11 @@ pub const StubsHelperSection = struct {
175 return s;175 return s;
176 }176 }
177177
178 pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void {178 pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
179 const tracy = trace(@src());179 const tracy = trace(@src());
180 defer tracy.end();180 defer tracy.end();
181181
182 try stubs_helper.writePreamble(macho_file, bw);182 try stubs_helper.writePreamble(macho_file, writer);
183183
184 const cpu_arch = macho_file.getTarget().cpu.arch;184 const cpu_arch = macho_file.getTarget().cpu.arch;
185 const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];185 const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
...@@ -195,24 +195,24 @@ pub const StubsHelperSection = struct {...@@ -195,24 +195,24 @@ pub const StubsHelperSection = struct {
195 const target: i64 = @intCast(sect.addr);195 const target: i64 = @intCast(sect.addr);
196 switch (cpu_arch) {196 switch (cpu_arch) {
197 .x86_64 => {197 .x86_64 => {
198 try bw.writeByte(0x68);198 try writer.writeByte(0x68);
199 try bw.writeInt(u32, offset, .little);199 try writer.writeInt(u32, offset, .little);
200 try bw.writeByte(0xe9);200 try writer.writeByte(0xe9);
201 try bw.writeInt(i32, @intCast(target - source - 6 - 4), .little);201 try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);
202 },202 },
203 .aarch64 => {203 .aarch64 => {
204 const literal = blk: {204 const literal = blk: {
205 const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);205 const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);
206 break :blk std.math.cast(u18, div_res) orelse return error.Overflow;206 break :blk std.math.cast(u18, div_res) orelse return error.Overflow;
207 };207 };
208 try bw.writeInt(u32, aarch64.Instruction.ldrLiteral(208 try writer.writeInt(u32, aarch64.Instruction.ldrLiteral(
209 .w16,209 .w16,
210 literal,210 literal,
211 ).toU32(), .little);211 ).toU32(), .little);
212 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse212 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse
213 return error.Overflow;213 return error.Overflow;
214 try bw.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);214 try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
215 try bw.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });215 try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
216 },216 },
217 else => unreachable,217 else => unreachable,
218 }218 }
...@@ -220,7 +220,7 @@ pub const StubsHelperSection = struct {...@@ -220,7 +220,7 @@ pub const StubsHelperSection = struct {
220 }220 }
221 }221 }
222222
223 fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void {223 fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
224 _ = stubs_helper;224 _ = stubs_helper;
225 const obj = macho_file.getInternalObject().?;225 const obj = macho_file.getInternalObject().?;
226 const cpu_arch = macho_file.getTarget().cpu.arch;226 const cpu_arch = macho_file.getTarget().cpu.arch;
...@@ -235,21 +235,21 @@ pub const StubsHelperSection = struct {...@@ -235,21 +235,21 @@ pub const StubsHelperSection = struct {
235 };235 };
236 switch (cpu_arch) {236 switch (cpu_arch) {
237 .x86_64 => {237 .x86_64 => {
238 try bw.writeAll(&.{ 0x4c, 0x8d, 0x1d });238 try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d });
239 try bw.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);239 try writer.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);
240 try bw.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });240 try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
241 try bw.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);241 try writer.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);
242 try bw.writeByte(0x90);242 try writer.writeByte(0x90);
243 },243 },
244 .aarch64 => {244 .aarch64 => {
245 {245 {
246 // TODO relax if possible246 // TODO relax if possible
247 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));247 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));
248 try bw.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);248 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
249 const off: u12 = @truncate(dyld_private_addr);249 const off: u12 = @truncate(dyld_private_addr);
250 try bw.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);250 try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
251 }251 }
252 try bw.writeInt(u32, aarch64.Instruction.stp(252 try writer.writeInt(u32, aarch64.Instruction.stp(
253 .x16,253 .x16,
254 .x17,254 .x17,
255 aarch64.Register.sp,255 aarch64.Register.sp,
...@@ -258,15 +258,15 @@ pub const StubsHelperSection = struct {...@@ -258,15 +258,15 @@ pub const StubsHelperSection = struct {
258 {258 {
259 // TODO relax if possible259 // TODO relax if possible
260 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));260 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));
261 try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);261 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
262 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);262 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);
263 try bw.writeInt(u32, aarch64.Instruction.ldr(263 try writer.writeInt(u32, aarch64.Instruction.ldr(
264 .x16,264 .x16,
265 .x16,265 .x16,
266 aarch64.Instruction.LoadStoreOffset.imm(off),266 aarch64.Instruction.LoadStoreOffset.imm(off),
267 ).toU32(), .little);267 ).toU32(), .little);
268 }268 }
269 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);269 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
270 },270 },
271 else => unreachable,271 else => unreachable,
272 }272 }
...@@ -279,7 +279,7 @@ pub const LaSymbolPtrSection = struct {...@@ -279,7 +279,7 @@ pub const LaSymbolPtrSection = struct {
279 return macho_file.stubs.symbols.items.len * @sizeOf(u64);279 return macho_file.stubs.symbols.items.len * @sizeOf(u64);
280 }280 }
281281
282 pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, bw: *Writer) !void {282 pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void {
283 const tracy = trace(@src());283 const tracy = trace(@src());
284 defer tracy.end();284 defer tracy.end();
285 _ = laptr;285 _ = laptr;
...@@ -290,12 +290,12 @@ pub const LaSymbolPtrSection = struct {...@@ -290,12 +290,12 @@ pub const LaSymbolPtrSection = struct {
290 const sym = ref.getSymbol(macho_file).?;290 const sym = ref.getSymbol(macho_file).?;
291 if (sym.flags.weak) {291 if (sym.flags.weak) {
292 const value = sym.getAddress(.{ .stubs = false }, macho_file);292 const value = sym.getAddress(.{ .stubs = false }, macho_file);
293 try bw.writeInt(u64, @intCast(value), .little);293 try writer.writeInt(u64, @intCast(value), .little);
294 } else {294 } else {
295 const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) +295 const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) +
296 StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx;296 StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx;
297 stub_helper_idx += 1;297 stub_helper_idx += 1;
298 try bw.writeInt(u64, @intCast(value), .little);298 try writer.writeInt(u64, @intCast(value), .little);
299 }299 }
300 }300 }
301 }301 }
...@@ -329,16 +329,16 @@ pub const TlvPtrSection = struct {...@@ -329,16 +329,16 @@ pub const TlvPtrSection = struct {
329 return tlv.symbols.items.len * @sizeOf(u64);329 return tlv.symbols.items.len * @sizeOf(u64);
330 }330 }
331331
332 pub fn write(tlv: TlvPtrSection, macho_file: *MachO, bw: *Writer) !void {332 pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void {
333 const tracy = trace(@src());333 const tracy = trace(@src());
334 defer tracy.end();334 defer tracy.end();
335335
336 for (tlv.symbols.items) |ref| {336 for (tlv.symbols.items) |ref| {
337 const sym = ref.getSymbol(macho_file).?;337 const sym = ref.getSymbol(macho_file).?;
338 if (sym.flags.import) {338 if (sym.flags.import) {
339 try bw.writeInt(u64, 0, .little);339 try writer.writeInt(u64, 0, .little);
340 } else {340 } else {
341 try bw.writeInt(u64, sym.getAddress(.{}, macho_file), .little);341 try writer.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
342 }342 }
343 }343 }
344 }344 }
...@@ -400,7 +400,7 @@ pub const ObjcStubsSection = struct {...@@ -400,7 +400,7 @@ pub const ObjcStubsSection = struct {
400 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);400 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
401 }401 }
402402
403 pub fn write(objc: ObjcStubsSection, macho_file: *MachO, bw: *Writer) !void {403 pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: anytype) !void {
404 const tracy = trace(@src());404 const tracy = trace(@src());
405 defer tracy.end();405 defer tracy.end();
406406
...@@ -411,18 +411,18 @@ pub const ObjcStubsSection = struct {...@@ -411,18 +411,18 @@ pub const ObjcStubsSection = struct {
411 const addr = objc.getAddress(@intCast(idx), macho_file);411 const addr = objc.getAddress(@intCast(idx), macho_file);
412 switch (macho_file.getTarget().cpu.arch) {412 switch (macho_file.getTarget().cpu.arch) {
413 .x86_64 => {413 .x86_64 => {
414 try bw.writeAll(&.{ 0x48, 0x8b, 0x35 });414 try writer.writeAll(&.{ 0x48, 0x8b, 0x35 });
415 {415 {
416 const target = sym.getObjcSelrefsAddress(macho_file);416 const target = sym.getObjcSelrefsAddress(macho_file);
417 const source = addr;417 const source = addr;
418 try bw.writeInt(i32, @intCast(target - source - 3 - 4), .little);418 try writer.writeInt(i32, @intCast(target - source - 3 - 4), .little);
419 }419 }
420 try bw.writeAll(&.{ 0xff, 0x25 });420 try writer.writeAll(&.{ 0xff, 0x25 });
421 {421 {
422 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;422 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
423 const target = target_sym.getGotAddress(macho_file);423 const target = target_sym.getGotAddress(macho_file);
424 const source = addr + 7;424 const source = addr + 7;
425 try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little);425 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
426 }426 }
427 },427 },
428 .aarch64 => {428 .aarch64 => {
...@@ -430,9 +430,9 @@ pub const ObjcStubsSection = struct {...@@ -430,9 +430,9 @@ pub const ObjcStubsSection = struct {
430 const target = sym.getObjcSelrefsAddress(macho_file);430 const target = sym.getObjcSelrefsAddress(macho_file);
431 const source = addr;431 const source = addr;
432 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));432 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
433 try bw.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);433 try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
434 const off = try math.divExact(u12, @truncate(target), 8);434 const off = try math.divExact(u12, @truncate(target), 8);
435 try bw.writeInt(435 try writer.writeInt(
436 u32,436 u32,
437 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),437 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
438 .little,438 .little,
...@@ -443,18 +443,18 @@ pub const ObjcStubsSection = struct {...@@ -443,18 +443,18 @@ pub const ObjcStubsSection = struct {
443 const target = target_sym.getGotAddress(macho_file);443 const target = target_sym.getGotAddress(macho_file);
444 const source = addr + 2 * @sizeOf(u32);444 const source = addr + 2 * @sizeOf(u32);
445 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));445 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
446 try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);446 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
447 const off = try math.divExact(u12, @truncate(target), 8);447 const off = try math.divExact(u12, @truncate(target), 8);
448 try bw.writeInt(448 try writer.writeInt(
449 u32,449 u32,
450 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),450 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
451 .little,451 .little,
452 );452 );
453 }453 }
454 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);454 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
455 try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);455 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
456 try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);456 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
457 try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);457 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
458 },458 },
459 else => unreachable,459 else => unreachable,
460 }460 }
...@@ -496,7 +496,7 @@ pub const Indsymtab = struct {...@@ -496,7 +496,7 @@ pub const Indsymtab = struct {
496 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);496 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
497 }497 }
498498
499 pub fn write(ind: Indsymtab, macho_file: *MachO, bw: *Writer) !void {499 pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void {
500 const tracy = trace(@src());500 const tracy = trace(@src());
501 defer tracy.end();501 defer tracy.end();
502502
...@@ -505,21 +505,21 @@ pub const Indsymtab = struct {...@@ -505,21 +505,21 @@ pub const Indsymtab = struct {
505 for (macho_file.stubs.symbols.items) |ref| {505 for (macho_file.stubs.symbols.items) |ref| {
506 const sym = ref.getSymbol(macho_file).?;506 const sym = ref.getSymbol(macho_file).?;
507 if (sym.getOutputSymtabIndex(macho_file)) |idx| {507 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
508 try bw.writeInt(u32, idx, .little);508 try writer.writeInt(u32, idx, .little);
509 }509 }
510 }510 }
511511
512 for (macho_file.got.symbols.items) |ref| {512 for (macho_file.got.symbols.items) |ref| {
513 const sym = ref.getSymbol(macho_file).?;513 const sym = ref.getSymbol(macho_file).?;
514 if (sym.getOutputSymtabIndex(macho_file)) |idx| {514 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
515 try bw.writeInt(u32, idx, .little);515 try writer.writeInt(u32, idx, .little);
516 }516 }
517 }517 }
518518
519 for (macho_file.stubs.symbols.items) |ref| {519 for (macho_file.stubs.symbols.items) |ref| {
520 const sym = ref.getSymbol(macho_file).?;520 const sym = ref.getSymbol(macho_file).?;
521 if (sym.getOutputSymtabIndex(macho_file)) |idx| {521 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
522 try bw.writeInt(u32, idx, .little);522 try writer.writeInt(u32, idx, .little);
523 }523 }
524 }524 }
525 }525 }
...@@ -573,7 +573,7 @@ pub const DataInCode = struct {...@@ -573,7 +573,7 @@ pub const DataInCode = struct {
573 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;573 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;
574 }574 }
575575
576 pub fn write(dice: DataInCode, macho_file: *MachO, bw: *Writer) !void {576 pub fn write(dice: DataInCode, macho_file: *MachO, writer: anytype) !void {
577 const base_address = if (!macho_file.base.isRelocatable())577 const base_address = if (!macho_file.base.isRelocatable())
578 macho_file.getTextSegment().vmaddr578 macho_file.getTextSegment().vmaddr
579 else579 else
...@@ -581,7 +581,7 @@ pub const DataInCode = struct {...@@ -581,7 +581,7 @@ pub const DataInCode = struct {
581 for (dice.entries.items) |entry| {581 for (dice.entries.items) |entry| {
582 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);582 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);
583 const offset = atom_address + entry.offset - base_address;583 const offset = atom_address + entry.offset - base_address;
584 try bw.writeStruct(macho.data_in_code_entry{584 try writer.writeStruct(macho.data_in_code_entry{
585 .offset = @intCast(offset),585 .offset = @intCast(offset),
586 .length = entry.length,586 .length = entry.length,
587 .kind = entry.kind,587 .kind = entry.kind,