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 },
4141uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },
4242codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },
4343
44pagezero_seg_index: ?u4 = null,
45text_seg_index: ?u4 = null,
46linkedit_seg_index: ?u4 = null,
44pagezero_seg_index: ?u8 = null,
45text_seg_index: ?u8 = null,
46linkedit_seg_index: ?u8 = null,
4747text_sect_index: ?u8 = null,
4848data_sect_index: ?u8 = null,
4949got_sect_index: ?u8 = null,
......@@ -76,10 +76,10 @@ unwind_info: UnwindInfo = .{},
7676data_in_code: DataInCode = .{},
7777
7878/// Tracked loadable segments during incremental linking.
79zig_text_seg_index: ?u4 = null,
80zig_const_seg_index: ?u4 = null,
81zig_data_seg_index: ?u4 = null,
82zig_bss_seg_index: ?u4 = null,
79zig_text_seg_index: ?u8 = null,
80zig_const_seg_index: ?u8 = null,
81zig_data_seg_index: ?u8 = null,
82zig_bss_seg_index: ?u8 = null,
8383
8484/// Tracked section headers with incremental updates to Zig object.
8585zig_text_sect_index: ?u8 = null,
......@@ -591,7 +591,6 @@ pub fn flush(
591591 error.NoSpaceLeft => unreachable,
592592 error.OutOfMemory => return error.OutOfMemory,
593593 error.LinkFailure => return error.LinkFailure,
594 else => unreachable,
595594 };
596595 try self.writeHeader(ncmds, sizeofcmds);
597596 self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) {
......@@ -1075,7 +1074,7 @@ fn accessLibPath(
10751074
10761075 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
10771076 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 });
10791078 try checked_paths.append(try arena.dupe(u8, test_path.items));
10801079 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
10811080 error.FileNotFound => continue,
......@@ -1098,7 +1097,7 @@ fn accessFrameworkPath(
10981097
10991098 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
11001099 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}", .{
11021101 search_dir,
11031102 name,
11041103 name,
......@@ -1179,9 +1178,9 @@ fn parseDependentDylibs(self: *MachO) !void {
11791178 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
11801179 test_path.clearRetainingCapacity();
11811180 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 });
11831182 } else {
1184 try test_path.print("{s}{s}", .{ path, ext });
1183 try test_path.writer().print("{s}{s}", .{ path, ext });
11851184 }
11861185 try checked_paths.append(try arena.dupe(u8, test_path.items));
11871186 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
......@@ -2132,7 +2131,7 @@ fn initSegments(self: *MachO) !void {
21322131
21332132 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);
21362135 defer gpa.free(backlinks);
21372136 for (entries.items, 0..) |entry, i| {
21382137 backlinks[entry.index] = @intCast(i);
......@@ -2146,7 +2145,7 @@ fn initSegments(self: *MachO) !void {
21462145 self.segments.appendAssumeCapacity(segments[sorted.index]);
21472146 }
21482147
2149 for (&[_]*?u4{
2148 for (&[_]*?u8{
21502149 &self.pagezero_seg_index,
21512150 &self.text_seg_index,
21522151 &self.linkedit_seg_index,
......@@ -2164,7 +2163,7 @@ fn initSegments(self: *MachO) !void {
21642163 for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| {
21652164 const segname = header.segName();
21662165 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));
21682167 const protection = getSegmentProt(segname);
21692168 try self.segments.append(gpa, .{
21702169 .cmdsize = @sizeOf(macho.segment_command_64),
......@@ -2527,8 +2526,10 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
25272526
25282527 const doWork = struct {
25292528 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()]);
2531 try th.write(macho_file, &bw);
2529 const off = try macho_file.cast(usize, th.value);
2530 const size = th.size();
2531 var stream = std.io.fixedBufferStream(buffer[off..][0..size]);
2532 try th.write(macho_file, stream.writer());
25322533 }
25332534 }.doWork;
25342535 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 {
25552556
25562557 const doWork = struct {
25572558 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {
2558 var bw: Writer = .fixed(buffer);
2559 var stream = std.io.fixedBufferStream(buffer);
25592560 switch (tag) {
25602561 .eh_frame => eh_frame.write(macho_file, buffer),
2561 .unwind_info => try macho_file.unwind_info.write(macho_file, &bw),
2562 .got => try macho_file.got.write(macho_file, &bw),
2563 .stubs => try macho_file.stubs.write(macho_file, &bw),
2564 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, &bw),
2565 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, &bw),
2566 .objc_stubs => try macho_file.objc_stubs.write(macho_file, &bw),
2562 .unwind_info => try macho_file.unwind_info.write(macho_file, buffer),
2563 .got => try macho_file.got.write(macho_file, stream.writer()),
2564 .stubs => try macho_file.stubs.write(macho_file, stream.writer()),
2565 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, stream.writer()),
2566 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, stream.writer()),
2567 .objc_stubs => try macho_file.objc_stubs.write(macho_file, stream.writer()),
25672568 }
25682569 }
25692570 }.doWork;
......@@ -2604,8 +2605,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {
26042605 try macho_file.lazy_bind_section.updateSize(macho_file);
26052606 const sect_id = macho_file.stubs_helper_sect_index.?;
26062607 const out = &macho_file.sections.items(.out)[sect_id];
2607 var bw: Writer = .fixed(out.items);
2608 try macho_file.stubs_helper.write(macho_file, &bw);
2608 var stream = std.io.fixedBufferStream(out.items);
2609 try macho_file.stubs_helper.write(macho_file, stream.writer());
26092610 }
26102611 }.doWork;
26112612 doWork(self) catch |err|
......@@ -2664,49 +2665,46 @@ fn writeDyldInfo(self: *MachO) !void {
26642665 needed_size += cmd.lazy_bind_size;
26652666 needed_size += cmd.export_size;
26662667
2667 var bw: Writer = .fixed(try gpa.alloc(u8, needed_size));
2668 defer gpa.free(bw.buffer);
2669 @memset(bw.buffer, 0);
2668 const buffer = try gpa.alloc(u8, needed_size);
2669 defer gpa.free(buffer);
2670 @memset(buffer, 0);
26702671
2671 try self.rebase_section.write(&bw);
2672 bw.end = cmd.bind_off - base_off;
2673 try self.bind_section.write(&bw);
2674 bw.end = cmd.weak_bind_off - base_off;
2675 try self.weak_bind_section.write(&bw);
2676 bw.end = cmd.lazy_bind_off - base_off;
2677 try self.lazy_bind_section.write(&bw);
2678 bw.end = cmd.export_off - base_off;
2679 try self.export_trie.write(&bw);
2680 try self.pwriteAll(bw.buffer, cmd.rebase_off);
2672 var stream = std.io.fixedBufferStream(buffer);
2673 const writer = stream.writer();
2674
2675 try self.rebase_section.write(writer);
2676 try stream.seekTo(cmd.bind_off - base_off);
2677 try self.bind_section.write(writer);
2678 try stream.seekTo(cmd.weak_bind_off - base_off);
2679 try self.weak_bind_section.write(writer);
2680 try stream.seekTo(cmd.lazy_bind_off - base_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);
26812685}
26822686
2683pub fn writeDataInCode(self: *MachO) link.File.FlushError!void {
2687pub fn writeDataInCode(self: *MachO) !void {
26842688 const tracy = trace(@src());
26852689 defer tracy.end();
26862690 const gpa = self.base.comp.gpa;
26872691 const cmd = self.data_in_code_cmd;
2688
2689 var bw: Writer = .fixed(try gpa.alloc(u8, self.data_in_code.size()));
2690 defer gpa.free(bw.buffer);
2691
2692 try self.data_in_code.write(self, &bw);
2693 assert(bw.end == bw.buffer.len);
2694 try self.pwriteAll(bw.buffer, cmd.dataoff);
2692 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size());
2693 defer buffer.deinit();
2694 try self.data_in_code.write(self, buffer.writer());
2695 try self.pwriteAll(buffer.items, cmd.dataoff);
26952696}
26962697
26972698fn writeIndsymtab(self: *MachO) !void {
26982699 const tracy = trace(@src());
26992700 defer tracy.end();
2700
27012701 const gpa = self.base.comp.gpa;
27022702 const cmd = self.dysymtab_cmd;
2703
2704 var bw: Writer = .fixed(try gpa.alloc(u8, @sizeOf(u32) * cmd.nindirectsyms));
2705 defer gpa.free(bw.buffer);
2706
2707 try self.indsymtab.write(self, &bw);
2708 assert(bw.end == bw.buffer.len);
2709 try self.pwriteAll(bw.buffer, cmd.indirectsymoff);
2703 const needed_size = cmd.nindirectsyms * @sizeOf(u32);
2704 var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size);
2705 defer buffer.deinit();
2706 try self.indsymtab.write(self, buffer.writer());
2707 try self.pwriteAll(buffer.items, cmd.indirectsymoff);
27102708}
27112709
27122710pub fn writeSymtabToFile(self: *MachO) !void {
......@@ -2816,12 +2814,15 @@ fn calcSymtabSize(self: *MachO) !void {
28162814 }
28172815}
28182816
2819fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
2817fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
28202818 const comp = self.base.comp;
28212819 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 defer gpa.free(bw.buffer);
2824 var stream = std.io.fixedBufferStream(buffer);
2825 const writer = stream.writer();
28252826
28262827 var ncmds: usize = 0;
28272828
......@@ -2830,26 +2831,26 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
28302831 const slice = self.sections.slice();
28312832 var sect_id: usize = 0;
28322833 for (self.segments.items) |seg| {
2833 try bw.writeStruct(seg);
2834 try writer.writeStruct(seg);
28342835 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
2835 try bw.writeStruct(header);
2836 try writer.writeStruct(header);
28362837 }
28372838 sect_id += seg.nsects;
28382839 }
28392840 ncmds += self.segments.items.len;
28402841 }
28412842
2842 try bw.writeStruct(self.dyld_info_cmd);
2843 try writer.writeStruct(self.dyld_info_cmd);
28432844 ncmds += 1;
2844 try bw.writeStruct(self.function_starts_cmd);
2845 try writer.writeStruct(self.function_starts_cmd);
28452846 ncmds += 1;
2846 try bw.writeStruct(self.data_in_code_cmd);
2847 try writer.writeStruct(self.data_in_code_cmd);
28472848 ncmds += 1;
2848 try bw.writeStruct(self.symtab_cmd);
2849 try writer.writeStruct(self.symtab_cmd);
28492850 ncmds += 1;
2850 try bw.writeStruct(self.dysymtab_cmd);
2851 try writer.writeStruct(self.dysymtab_cmd);
28512852 ncmds += 1;
2852 try load_commands.writeDylinkerLC(&bw);
2853 try load_commands.writeDylinkerLC(writer);
28532854 ncmds += 1;
28542855
28552856 if (self.getInternalObject()) |obj| {
......@@ -2860,7 +2861,7 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
28602861 0
28612862 else
28622863 @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{
28642865 .entryoff = entryoff,
28652866 .stacksize = self.base.stack_size,
28662867 });
......@@ -2869,35 +2870,35 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
28692870 }
28702871
28712872 if (self.base.isDynLib()) {
2872 try load_commands.writeDylibIdLC(self, &bw);
2873 try load_commands.writeDylibIdLC(self, writer);
28732874 ncmds += 1;
28742875 }
28752876
28762877 for (self.rpath_list) |rpath| {
2877 try load_commands.writeRpathLC(&bw, rpath);
2878 try load_commands.writeRpathLC(rpath, writer);
28782879 ncmds += 1;
28792880 }
28802881 if (comp.config.any_sanitize_thread) {
28812882 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
28822883 defer gpa.free(path);
28832884 const rpath = std.fs.path.dirname(path) orelse ".";
2884 try load_commands.writeRpathLC(&bw, rpath);
2885 try load_commands.writeRpathLC(rpath, writer);
28852886 ncmds += 1;
28862887 }
28872888
2888 try bw.writeStruct(macho.source_version_command{ .version = 0 });
2889 try writer.writeStruct(macho.source_version_command{ .version = 0 });
28892890 ncmds += 1;
28902891
28912892 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);
28932894 ncmds += 1;
28942895 } else {
2895 try load_commands.writeVersionMinLC(&bw, self.platform, self.sdk_version);
2896 try load_commands.writeVersionMinLC(self.platform, self.sdk_version, writer);
28962897 ncmds += 1;
28972898 }
28982899
2899 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + bw.count;
2900 try bw.writeStruct(self.uuid_cmd);
2900 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos;
2901 try writer.writeStruct(self.uuid_cmd);
29012902 ncmds += 1;
29022903
29032904 for (self.dylibs.items) |index| {
......@@ -2915,19 +2916,20 @@ fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
29152916 .timestamp = dylib_id.timestamp,
29162917 .current_version = dylib_id.current_version,
29172918 .compatibility_version = dylib_id.compatibility_version,
2918 }, &bw);
2919 }, writer);
29192920 ncmds += 1;
29202921 }
29212922
29222923 if (self.requiresCodeSig()) {
2923 try bw.writeStruct(self.codesig_cmd);
2924 try writer.writeStruct(self.codesig_cmd);
29242925 ncmds += 1;
29252926 }
29262927
2927 assert(bw.end == bw.buffer.len);
2928 try self.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
2928 assert(stream.pos == needed_size);
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 };
29312933}
29322934
29332935fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {
......@@ -3010,27 +3012,27 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
30103012}
30113013
30123014pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
3013 const gpa = self.base.comp.gpa;
30143015 const seg = self.getTextSegment();
30153016 const offset = self.codesig_cmd.dataoff;
30163017
3017 var bw: Writer = .fixed(try gpa.alloc(u8, code_sig.size()));
3018 defer gpa.free(bw.buffer);
3018 var buffer = std.ArrayList(u8).init(self.base.comp.gpa);
3019 defer buffer.deinit();
3020 try buffer.ensureTotalCapacityPrecise(code_sig.size());
30193021 try code_sig.writeAdhocSignature(self, .{
30203022 .file = self.base.file.?,
30213023 .exec_seg_base = seg.fileoff,
30223024 .exec_seg_limit = seg.filesize,
30233025 .file_size = offset,
30243026 .dylib = self.base.isDynLib(),
3025 }, &bw);
3027 }, buffer.writer());
3028 assert(buffer.items.len == code_sig.size());
30263029
30273030 log.debug("writing code signature from 0x{x} to 0x{x}", .{
30283031 offset,
3029 offset + bw.end,
3032 offset + buffer.items.len,
30303033 });
30313034
3032 assert(bw.end == bw.buffer.len);
3033 try self.pwriteAll(bw.buffer, offset);
3035 try self.pwriteAll(buffer.items, offset);
30343036}
30353037
30363038pub fn updateFunc(
......@@ -3339,7 +3341,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
33393341 }
33403342
33413343 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 {
33433345 const sect = &macho_file.sections.items(.header)[sect_id];
33443346 const seg = macho_file.segments.items[seg_id];
33453347 sect.addr = seg.vmaddr;
......@@ -3598,7 +3600,7 @@ inline fn requiresThunks(self: MachO) bool {
35983600}
35993601
36003602pub fn isZigSegment(self: MachO, seg_id: u8) bool {
3601 inline for (&[_]?u4{
3603 inline for (&[_]?u8{
36023604 self.zig_text_seg_index,
36033605 self.zig_const_seg_index,
36043606 self.zig_data_seg_index,
......@@ -3646,9 +3648,9 @@ pub fn addSegment(self: *MachO, name: []const u8, opts: struct {
36463648 fileoff: u64 = 0,
36473649 filesize: u64 = 0,
36483650 prot: macho.vm_prot_t = macho.PROT.NONE,
3649}) error{OutOfMemory}!u4 {
3651}) error{OutOfMemory}!u8 {
36503652 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));
36523654 try self.segments.append(gpa, .{
36533655 .segname = makeStaticString(name),
36543656 .vmaddr = opts.vmaddr,
......@@ -3698,9 +3700,9 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 {
36983700 return buf;
36993701}
37003702
3701pub fn getSegmentByName(self: MachO, segname: []const u8) ?u4 {
3703pub fn getSegmentByName(self: MachO, segname: []const u8) ?u8 {
37023704 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));
37043706 } else return null;
37053707}
37063708
......@@ -4028,7 +4030,7 @@ const default_entry_symbol_name = "_main";
40284030
40294031const Section = struct {
40304032 header: macho.section_64,
4031 segment_id: u4,
4033 segment_id: u8,
40324034 atoms: std.ArrayListUnmanaged(Ref) = .empty,
40334035 free_list: std.ArrayListUnmanaged(Atom.Index) = .empty,
40344036 last_atom_index: Atom.Index = 0,
......@@ -4353,7 +4355,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
43534355// The file/property is also available with vendored libc.
43544356fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {
43554357 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));
43574359 const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});
43584360 if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;
43594361 return error.SdkVersionFailure;
......@@ -4369,7 +4371,7 @@ fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion {
43694371 };
43704372
43714373 const parseNext = struct {
4372 fn parseNext(it: *std.mem.SplitIterator(u8, .any)) ?u16 {
4374 fn parseNext(it: anytype) ?u16 {
43734375 const nn = it.next() orelse return null;
43744376 return std.fmt.parseInt(u16, nn, 10) catch null;
43754377 }
......@@ -5317,11 +5319,8 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
53175319pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void {
53185320 const comp = macho_file.base.comp;
53195321 const diags = &comp.link_diags;
5320 var fw = macho_file.base.file.?.writer();
5321 fw.pos = offset;
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.?)}),
5322 macho_file.base.file.?.pwriteAll(bytes, offset) catch |err| {
5323 return diags.fail("failed to write: {s}", .{@errorName(err)});
53255324 };
53265325}
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
7171 .mtime = hdr.date() catch 0,
7272 };
7373
74 log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path });
74 log.debug("extracting object '{}' from archive '{}'", .{ object.path, path });
7575
7676 try self.objects.append(gpa, object);
7777 }
7878}
7979
8080pub fn writeHeader(
81 bw: *Writer,
8281 object_name: []const u8,
8382 object_size: usize,
8483 format: Format,
85) Writer.Error!void {
86 var hdr: ar_hdr = undefined;
87 @memset(mem.asBytes(&hdr), ' ');
88 inline for (@typeInfo(ar_hdr).@"struct".fields) |field| @field(hdr, field.name)[0] = '0';
84 writer: anytype,
85) !void {
86 var hdr: ar_hdr = .{
87 .ar_name = undefined,
88 .ar_date = undefined,
89 .ar_uid = undefined,
90 .ar_gid = undefined,
91 .ar_mode = undefined,
92 .ar_size = undefined,
93 .ar_fmag = undefined,
94 };
95 @memset(mem.asBytes(&hdr), 0x20);
96 inline for (@typeInfo(ar_hdr).@"struct".fields) |field| {
97 var stream = std.io.fixedBufferStream(&@field(hdr, field.name));
98 stream.writer().print("0", .{}) catch unreachable;
99 }
89100 @memcpy(&hdr.ar_fmag, ARFMAG);
101
90102 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;
92103 const total_object_size = object_size + object_name_len;
93 _ = std.fmt.bufPrint(&hdr.ar_size, "{d}", .{total_object_size}) catch unreachable;
94 try bw.writeStruct(hdr);
95 try bw.writeAll(object_name);
96 try bw.splatByteAll(0, object_name_len - object_name.len);
104
105 {
106 var stream = std.io.fixedBufferStream(&hdr.ar_name);
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 }
97121}
98122
99123// Archive files start with the ARMAG identifying string. Then follows a
......@@ -177,12 +201,12 @@ pub const ArSymtab = struct {
177201 return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
178202 }
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 {
181205 const ptr_width = ptrWidth(format);
182206 // Header
183 try writeHeader(bw, SYMDEF, ar.size(format), format);
207 try writeHeader(SYMDEF, ar.size(format), format, writer);
184208 // 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);
186210 // Symtab entries
187211 for (ar.entries.items) |entry| {
188212 const file_off = switch (macho_file.getFile(entry.file).?) {
......@@ -191,16 +215,19 @@ pub const ArSymtab = struct {
191215 else => unreachable,
192216 };
193217 // Name offset
194 try writeInt(bw, format, entry.off);
218 try writeInt(format, entry.off, writer);
195219 // File offset
196 try writeInt(bw, format, file_off);
220 try writeInt(format, file_off, writer);
197221 }
198222 // Strtab size
199223 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);
201226 // Strtab
202 try bw.writeAll(ar.strtab.buffer.items);
203 try bw.splatByteAll(0, strtab_size - ar.strtab.buffer.items.len);
227 try writer.writeAll(ar.strtab.buffer.items);
228 if (padding > 0) {
229 try writer.writeByteNTimes(0, padding);
230 }
204231 }
205232
206233 const PrintFormat = struct {
......@@ -248,10 +275,10 @@ pub fn ptrWidth(format: Format) usize {
248275 };
249276}
250277
251pub fn writeInt(bw: *Writer, format: Format, value: u64) Writer.Error!void {
278pub fn writeInt(format: Format, value: u64, writer: anytype) !void {
252279 switch (format) {
253 .p32 => try bw.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
254 .p64 => try bw.writeInt(u64, value, .little),
280 .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
281 .p64 => try writer.writeInt(u64, value, .little),
255282 }
256283}
257284
src/link/MachO/Atom.zig+45-41
......@@ -580,9 +580,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
580580
581581 relocs_log.debug("{x}: {s}", .{ self.value, name });
582582
583 var bw: Writer = .fixed(buffer);
584
585583 var has_error = false;
584 var stream = std.io.fixedBufferStream(buffer);
586585 var i: usize = 0;
587586 while (i < relocs.len) : (i += 1) {
588587 const rel = relocs[i];
......@@ -593,28 +592,30 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
593592 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;
594593 }
595594
596 bw.end = std.math.cast(usize, rel_offset) orelse return error.Overflow;
597 self.resolveRelocInner(rel, subtractor, buffer, macho_file, &bw) catch |err| switch (err) {
598 error.RelaxFail => {
599 const target = switch (rel.tag) {
600 .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),
601 .local => rel.getTargetAtom(self, macho_file).getName(macho_file),
602 };
603 try macho_file.reportParseError2(
604 file.getIndex(),
605 "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {f}, target {s}",
606 .{
607 name,
608 self.getAddress(macho_file),
609 rel.offset,
610 rel.fmtPretty(macho_file.getTarget().cpu.arch),
611 target,
612 },
613 );
614 has_error = true;
615 },
616 error.RelaxFailUnexpectedInstruction => has_error = true,
617 else => |e| return e,
595 try stream.seekTo(rel_offset);
596 self.resolveRelocInner(rel, subtractor, buffer, macho_file, stream.writer()) catch |err| {
597 switch (err) {
598 error.RelaxFail => {
599 const target = switch (rel.tag) {
600 .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),
601 .local => rel.getTargetAtom(self, macho_file).getName(macho_file),
602 };
603 try macho_file.reportParseError2(
604 file.getIndex(),
605 "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {}, target {s}",
606 .{
607 name,
608 self.getAddress(macho_file),
609 rel.offset,
610 rel.fmtPretty(macho_file.getTarget().cpu.arch),
611 target,
612 },
613 );
614 has_error = true;
615 },
616 error.RelaxFailUnexpectedInstruction => has_error = true,
617 else => |e| return e,
618 }
618619 };
619620 }
620621
......@@ -637,8 +638,8 @@ fn resolveRelocInner(
637638 subtractor: ?Relocation,
638639 code: []u8,
639640 macho_file: *MachO,
640 bw: *Writer,
641) Writer.Error!void {
641 writer: anytype,
642) ResolveError!void {
642643 const t = &macho_file.base.comp.root_mod.resolved_target.result;
643644 const cpu_arch = t.cpu.arch;
644645 const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;
......@@ -652,7 +653,7 @@ fn resolveRelocInner(
652653 const divExact = struct {
653654 fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {
654655 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}", .{
656657 atom.getName(ctx),
657658 r.fmtPretty(ctx.getTarget().cpu.arch),
658659 r.offset,
......@@ -689,14 +690,14 @@ fn resolveRelocInner(
689690 if (rel.tag == .@"extern") {
690691 const sym = rel.getTargetSymbol(self, macho_file);
691692 if (sym.isTlvInit(macho_file)) {
692 try bw.writeInt(u64, @intCast(S - TLS), .little);
693 try writer.writeInt(u64, @intCast(S - TLS), .little);
693694 return;
694695 }
695696 if (sym.flags.import) return;
696697 }
697 try bw.writeInt(u64, @bitCast(S + A - SUB), .little);
698 try writer.writeInt(u64, @bitCast(S + A - SUB), .little);
698699 } 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);
700701 } else unreachable;
701702 },
702703
......@@ -704,7 +705,7 @@ fn resolveRelocInner(
704705 assert(rel.tag == .@"extern");
705706 assert(rel.meta.length == 2);
706707 assert(rel.meta.pcrel);
707 try bw.writeInt(i32, @intCast(G + A - P), .little);
708 try writer.writeInt(i32, @intCast(G + A - P), .little);
708709 },
709710
710711 .branch => {
......@@ -713,7 +714,7 @@ fn resolveRelocInner(
713714 assert(rel.tag == .@"extern");
714715
715716 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),
717718 .aarch64 => {
718719 const disp: i28 = math.cast(i28, S + A - P) orelse blk: {
719720 const thunk = self.getThunk(macho_file);
......@@ -731,10 +732,10 @@ fn resolveRelocInner(
731732 assert(rel.meta.length == 2);
732733 assert(rel.meta.pcrel);
733734 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);
735736 } else {
736737 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);
738739 }
739740 },
740741
......@@ -745,17 +746,17 @@ fn resolveRelocInner(
745746 const sym = rel.getTargetSymbol(self, macho_file);
746747 if (sym.getSectionFlags().tlv_ptr) {
747748 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);
749750 } else {
750751 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);
752753 }
753754 },
754755
755756 .signed, .signed1, .signed2, .signed4 => {
756757 assert(rel.meta.length == 2);
757758 assert(rel.meta.pcrel);
758 try bw.writeInt(i32, @intCast(S + A - P), .little);
759 try writer.writeInt(i32, @intCast(S + A - P), .little);
759760 },
760761
761762 .page,
......@@ -807,7 +808,7 @@ fn resolveRelocInner(
807808 2 => try divExact(self, rel, @truncate(target), 4, macho_file),
808809 3 => try divExact(self, rel, @truncate(target), 8, macho_file),
809810 };
810 try bw.writeInt(u32, inst.toU32(), .little);
811 try writer.writeInt(u32, inst.toU32(), .little);
811812 }
812813 },
813814
......@@ -885,7 +886,7 @@ fn resolveRelocInner(
885886 .sf = @as(u1, @truncate(reg_info.size)),
886887 },
887888 };
888 try bw.writeInt(u32, inst.toU32(), .little);
889 try writer.writeInt(u32, inst.toU32(), .little);
889890 },
890891 }
891892}
......@@ -937,8 +938,11 @@ const x86_64 = struct {
937938 }
938939
939940 fn encode(insts: []const Instruction, code: []u8) !void {
940 var bw: Writer = .fixed(code);
941 for (insts) |inst| try inst.encode(&bw, .{});
941 var stream = std.io.fixedBufferStream(code);
942 const writer = stream.writer();
943 for (insts) |inst| {
944 try inst.encode(writer, .{});
945 }
942946 }
943947
944948 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 {
247247pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void {
248248 const file = try fs.cwd().openFile(path, .{});
249249 defer file.close();
250 const inner = try file.readToEndAlloc(allocator, .unlimited);
250 const inner = try file.readToEndAlloc(allocator, std.math.maxInt(u32));
251251 self.entitlements = .{ .inner = inner };
252252}
253253
......@@ -304,11 +304,10 @@ pub fn writeAdhocSignature(
304304 var hash: [hash_size]u8 = undefined;
305305
306306 if (self.requirements) |*req| {
307 var aw: std.io.Writer.Allocating = .init(allocator);
308 defer aw.deinit();
309
310 try req.write(&aw.writer);
311 Sha256.hash(aw.getWritten(), &hash, .{});
307 var buf = std.ArrayList(u8).init(allocator);
308 defer buf.deinit();
309 try req.write(buf.writer());
310 Sha256.hash(buf.items, &hash, .{});
312311 self.code_directory.addSpecialHash(req.slotType(), hash);
313312
314313 try blobs.append(.{ .requirements = req });
......@@ -317,11 +316,10 @@ pub fn writeAdhocSignature(
317316 }
318317
319318 if (self.entitlements) |*ents| {
320 var aw: std.io.Writer.Allocating = .init(allocator);
321 defer aw.deinit();
322
323 try ents.write(&aw.writer);
324 Sha256.hash(aw.getWritten(), &hash, .{});
319 var buf = std.ArrayList(u8).init(allocator);
320 defer buf.deinit();
321 try ents.write(buf.writer());
322 Sha256.hash(buf.items, &hash, .{});
325323 self.code_directory.addSpecialHash(ents.slotType(), hash);
326324
327325 try blobs.append(.{ .entitlements = ents });
src/link/MachO/DebugSymbols.zig+16-11
......@@ -269,14 +269,18 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
269269
270270fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } {
271271 const gpa = self.allocator;
272 var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeDsym(macho_file, self)));
273 defer gpa.free(bw.buffer);
272 const needed_size = load_commands.calcLoadCommandsSizeDsym(macho_file, self);
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
275279 var ncmds: usize = 0;
276280
277281 // UUID comes first presumably to speed up lookup by the consumer like lldb.
278282 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);
279 try bw.writeStruct(self.uuid_cmd);
283 try writer.writeStruct(self.uuid_cmd);
280284 ncmds += 1;
281285
282286 // Segment and section load commands
......@@ -289,11 +293,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
289293 var out_seg = seg;
290294 out_seg.fileoff = 0;
291295 out_seg.filesize = 0;
292 try bw.writeStruct(out_seg);
296 try writer.writeStruct(out_seg);
293297 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
294298 var out_header = header;
295299 out_header.offset = 0;
296 try bw.writeStruct(out_header);
300 try writer.writeStruct(out_header);
297301 }
298302 sect_id += seg.nsects;
299303 }
......@@ -302,22 +306,23 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
302306 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
303307 sect_id = 0;
304308 for (self.segments.items) |seg| {
305 try bw.writeStruct(seg);
309 try writer.writeStruct(seg);
306310 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
307 try bw.writeStruct(header);
311 try writer.writeStruct(header);
308312 }
309313 sect_id += seg.nsects;
310314 }
311315 ncmds += self.segments.items.len;
312316 }
313317
314 try bw.writeStruct(self.symtab_cmd);
318 try writer.writeStruct(self.symtab_cmd);
315319 ncmds += 1;
316320
317 assert(bw.end == bw.buffer.len);
318 try self.file.?.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
321 assert(stream.pos == needed_size);
322
323 try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
319324
320 return .{ ncmds, bw.end };
325 return .{ ncmds, buffer.len };
321326}
322327
323328fn 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 {
8181 .dwarf64 => 12,
8282 } + cuh_length;
8383 while (p.pos < end_pos) {
84 const di_code = try p.readLeb128(u64);
84 const di_code = try p.readUleb128(u64);
8585 if (di_code == 0) return error.UnexpectedEndOfFile;
8686 if (di_code == code) return;
8787
......@@ -174,14 +174,14 @@ pub const InfoReader = struct {
174174 dw.FORM.block1 => try p.readByte(),
175175 dw.FORM.block2 => try p.readInt(u16),
176176 dw.FORM.block4 => try p.readInt(u32),
177 dw.FORM.block => try p.readLeb128(u64),
177 dw.FORM.block => try p.readUleb128(u64),
178178 else => unreachable,
179179 };
180180 return p.readNBytes(len);
181181 }
182182
183183 pub fn readExprLoc(p: *InfoReader) ![]const u8 {
184 const len: u64 = try p.readLeb128(u64);
184 const len: u64 = try p.readUleb128(u64);
185185 return p.readNBytes(len);
186186 }
187187
......@@ -191,8 +191,8 @@ pub const InfoReader = struct {
191191 dw.FORM.data2, dw.FORM.ref2 => try p.readInt(u16),
192192 dw.FORM.data4, dw.FORM.ref4 => try p.readInt(u32),
193193 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),
195 dw.FORM.sdata => @bitCast(try p.readLeb128(i64)),
194 dw.FORM.udata, dw.FORM.ref_udata => try p.readUleb128(u64),
195 dw.FORM.sdata => @bitCast(try p.readIleb128(i64)),
196196 else => return error.UnhandledConstantForm,
197197 };
198198 }
......@@ -203,7 +203,7 @@ pub const InfoReader = struct {
203203 dw.FORM.strx2, dw.FORM.addrx2 => try p.readInt(u16),
204204 dw.FORM.strx3, dw.FORM.addrx3 => error.UnhandledForm,
205205 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),
207207 else => return error.UnhandledIndexForm,
208208 };
209209 }
......@@ -272,10 +272,20 @@ pub const InfoReader = struct {
272272 };
273273 }
274274
275 pub fn readLeb128(p: *InfoReader, comptime Type: type) !Type {
276 var r: std.io.Reader = .fixed(p.bytes()[p.pos..]);
277 defer p.pos += r.seek;
278 return r.takeLeb128(Type);
275 pub fn readUleb128(p: *InfoReader, comptime Type: type) !Type {
276 var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
277 var creader = std.io.countingReader(stream.reader());
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;
279289 }
280290
281291 pub fn seekTo(p: *InfoReader, off: u64) !void {
......@@ -297,10 +307,10 @@ pub const AbbrevReader = struct {
297307
298308 pub fn readDecl(p: *AbbrevReader) !?AbbrevDecl {
299309 const pos = p.pos;
300 const code = try p.readLeb128(Code);
310 const code = try p.readUleb128(Code);
301311 if (code == 0) return null;
302312
303 const tag = try p.readLeb128(Tag);
313 const tag = try p.readUleb128(Tag);
304314 const has_children = (try p.readByte()) > 0;
305315 return .{
306316 .code = code,
......@@ -313,8 +323,8 @@ pub const AbbrevReader = struct {
313323
314324 pub fn readAttr(p: *AbbrevReader) !?AbbrevAttr {
315325 const pos = p.pos;
316 const at = try p.readLeb128(At);
317 const form = try p.readLeb128(Form);
326 const at = try p.readUleb128(At);
327 const form = try p.readUleb128(Form);
318328 return if (at == 0 and form == 0) null else .{
319329 .at = at,
320330 .form = form,
......@@ -329,10 +339,12 @@ pub const AbbrevReader = struct {
329339 return p.bytes()[p.pos];
330340 }
331341
332 pub fn readLeb128(p: *AbbrevReader, comptime Type: type) !Type {
333 var r: std.io.Reader = .fixed(p.bytes()[p.pos..]);
334 defer p.pos += r.seek;
335 return r.takeLeb128(Type);
342 pub fn readUleb128(p: *AbbrevReader, comptime Type: type) !Type {
343 var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
344 var creader = std.io.countingReader(stream.reader());
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;
336348 }
337349
338350 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 {
158158 }
159159}
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
161201pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void {
162202 try self.exports.append(allocator, .{
163203 .name = try self.addString(allocator, name),
......@@ -167,16 +207,16 @@ pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Ex
167207
168208fn parseTrieNode(
169209 self: *Dylib,
170 br: *std.io.Reader,
210 it: *TrieIterator,
171211 allocator: Allocator,
172212 arena: Allocator,
173213 prefix: []const u8,
174214) !void {
175215 const tracy = trace(@src());
176216 defer tracy.end();
177 const size = try br.takeLeb128(u64);
217 const size = try it.readUleb128();
178218 if (size > 0) {
179 const flags = try br.takeLeb128(u8);
219 const flags = try it.readUleb128();
180220 const kind = flags & macho.EXPORT_SYMBOL_FLAGS_KIND_MASK;
181221 const out_flags = Export.Flags{
182222 .abs = kind == macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE,
......@@ -184,28 +224,29 @@ fn parseTrieNode(
184224 .weak = flags & macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION != 0,
185225 };
186226 if (flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT != 0) {
187 _ = try br.takeLeb128(u64); // dylib ordinal
188 const name = try br.takeSentinel(0);
227 _ = try it.readUleb128(); // dylib ordinal
228 const name = try it.readString();
189229 try self.addExport(allocator, if (name.len > 0) name else prefix, out_flags);
190230 } else if (flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER != 0) {
191 _ = try br.takeLeb128(u64); // stub offset
192 _ = try br.takeLeb128(u64); // resolver offset
231 _ = try it.readUleb128(); // stub offset
232 _ = try it.readUleb128(); // resolver offset
193233 try self.addExport(allocator, prefix, out_flags);
194234 } else {
195 _ = try br.takeLeb128(u64); // VM offset
235 _ = try it.readUleb128(); // VM offset
196236 try self.addExport(allocator, prefix, out_flags);
197237 }
198238 }
199239
200 const nedges = try br.takeByte();
240 const nedges = try it.readByte();
241
201242 for (0..nedges) |_| {
202 const label = try br.takeSentinel(0);
203 const off = try br.takeLeb128(usize);
243 const label = try it.readString();
244 const off = try it.readUleb128();
204245 const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label });
205 const seek = br.seek;
206 br.seek = off;
207 try self.parseTrieNode(br, allocator, arena, prefix_label);
208 br.seek = seek;
246 const curr = it.pos;
247 it.pos = math.cast(usize, off) orelse return error.Overflow;
248 try self.parseTrieNode(it, allocator, arena, prefix_label);
249 it.pos = curr;
209250 }
210251}
211252
......@@ -216,8 +257,8 @@ fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void {
216257 var arena = std.heap.ArenaAllocator.init(gpa);
217258 defer arena.deinit();
218259
219 var r: std.io.Reader = .fixed(data);
220 try self.parseTrieNode(&r, gpa, arena.allocator(), "");
260 var it: TrieIterator = .{ .data = data };
261 try self.parseTrieNode(&it, gpa, arena.allocator(), "");
221262}
222263
223264fn 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
261261
262262 sect.offset = @intCast(self.objc_methnames.items.len);
263263 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
266266 const name_str = try self.addString(gpa, "ltmp");
267267 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
10691069 }
10701070 }
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 };
10731073 while (try it.next()) |rec| {
10741074 switch (rec.tag) {
10751075 .cie => try self.cies.append(allocator, .{
......@@ -1698,11 +1698,11 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
16981698 };
16991699}
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 {
17021702 // Header
17031703 const size = try macho_file.cast(usize, self.output_ar_state.size);
17041704 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);
17061706 // Data
17071707 const file = macho_file.getFileHandle(self.file_handle);
17081708 // TODO try using copyRangeAll
......@@ -1711,7 +1711,7 @@ pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file:
17111711 defer gpa.free(data);
17121712 const amt = try file.preadAll(data, self.offset);
17131713 if (amt != size) return error.InputOutput;
1714 try bw.writeAll(data);
1714 try writer.writeAll(data);
17151715}
17161716
17171717pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
......@@ -1865,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
18651865 }
18661866 gpa.free(sections_data);
18671867 }
1868 @memset(sections_data, &.{});
1868 @memset(sections_data, &[0]u8{});
18691869 const file = macho_file.getFileHandle(self.file_handle);
18701870
18711871 for (headers, 0..) |header, n_sect| {
src/link/MachO/Symbol.zig+1-1
......@@ -297,7 +297,7 @@ const Format = struct {
297297 symbol: Symbol,
298298 macho_file: *MachO,
299299
300 fn format2(f: Format, w: *Writer) Writer.Error!void {
300 fn default(f: Format, w: *Writer) Writer.Error!void {
301301 const symbol = f.symbol;
302302 try w.print("%{d} : {s} : @{x}", .{
303303 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 {
2020 return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;
2121}
2222
23pub fn write(thunk: Thunk, macho_file: *MachO, bw: *Writer) !void {
23pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
2424 for (thunk.symbols.keys(), 0..) |ref, i| {
2525 const sym = ref.getSymbol(macho_file).?;
2626 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
2727 const taddr = sym.getAddress(.{}, macho_file);
2828 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);
3030 const off: u12 = @truncate(taddr);
31 try bw.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
32 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
31 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
32 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
3333 }
3434}
3535
src/link/MachO/UnwindInfo.zig+18-12
......@@ -289,10 +289,13 @@ pub fn calcSize(info: UnwindInfo) usize {
289289 return total_size;
290290}
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 {
293293 const seg = macho_file.getTextSegment();
294294 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
296299 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);
297300 const common_encodings_count: u32 = info.common_encodings_count;
298301 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
300303 const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);
301304 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{
304307 .commonEncodingsArraySectionOffset = common_encodings_offset,
305308 .commonEncodingsArrayCount = common_encodings_count,
306309 .personalityArraySectionOffset = personalities_offset,
......@@ -309,11 +312,11 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
309312 .indexCount = indexes_count,
310313 });
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
314317 for (info.personalities[0..info.personalities_count]) |ref| {
315318 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);
317320 }
318321
319322 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
322325 for (info.pages.items, 0..) |page, i| {
323326 assert(page.count > 0);
324327 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{
326329 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
327330 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
328331 .lsdaIndexArraySectionOffset = lsda_base_offset +
......@@ -332,7 +335,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
332335
333336 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);
334337 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{
336339 .functionOffset = sentinel_address,
337340 .secondLevelPagesSectionOffset = 0,
338341 .lsdaIndexArraySectionOffset = lsda_base_offset +
......@@ -341,20 +344,23 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!voi
341344
342345 for (info.lsdas.items) |index| {
343346 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{
345348 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
346349 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),
347350 });
348351 }
349352
350353 for (info.pages.items) |page| {
351 const start = bw.count;
352 try page.write(info, macho_file, bw);
353 const nwritten = bw.count - start;
354 try bw.splatByteAll(0, math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow);
354 const start = stream.pos;
355 try page.write(info, macho_file, writer);
356 const nwritten = stream.pos - start;
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 }
355361 }
356362
357 @memset(bw.unusedCapacitySlice(), 0);
363 @memset(buffer[stream.pos..], 0);
358364}
359365
360366fn 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 {
317317 self.output_ar_state.size = self.data.items.len;
318318}
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 {
321321 // Header
322322 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);
324324 // Data
325 try bw.writeAll(self.data.items);
325 try writer.writeAll(self.data.items);
326326}
327327
328328pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void {
......@@ -884,6 +884,7 @@ pub fn updateNav(
884884 defer debug_wip_nav.deinit();
885885 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
886886 error.OutOfMemory => return error.OutOfMemory,
887 error.Overflow => return error.Overflow,
887888 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
888889 };
889890 }
......@@ -920,6 +921,7 @@ pub fn updateNav(
920921
921922 if (debug_wip_nav) |*wip_nav| self.dwarf.?.finishWipNav(pt, nav_index, wip_nav) catch |err| switch (err) {
922923 error.OutOfMemory => return error.OutOfMemory,
924 error.Overflow => return error.Overflow,
923925 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
924926 };
925927 } 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,
33
44pub const Entry = struct {
55 offset: u64,
6 segment_id: u4,
6 segment_id: u8,
77
88 pub fn lessThan(ctx: void, entry: Entry, other: Entry) bool {
99 _ = ctx;
......@@ -110,35 +110,33 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
110110fn finalize(rebase: *Rebase, gpa: Allocator) !void {
111111 if (rebase.entries.items.len == 0) return;
112112
113 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &rebase.buffer);
114 const bw = &aw.writer;
115 defer rebase.buffer = aw.toArrayList();
113 const writer = rebase.buffer.writer(gpa);
116114
117115 log.debug("rebase opcodes", .{});
118116
119117 std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);
120118
121 try setTypePointer(bw);
119 try setTypePointer(writer);
122120
123121 var start: usize = 0;
124122 var seg_id: ?u8 = null;
125123 for (rebase.entries.items, 0..) |entry, i| {
126124 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);
128126 seg_id = entry.segment_id;
129127 start = i;
130128 }
131129
132 try finalizeSegment(rebase.entries.items[start..], bw);
133 try done(bw);
130 try finalizeSegment(rebase.entries.items[start..], writer);
131 try done(writer);
134132}
135133
136fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
134fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
137135 if (entries.len == 0) return;
138136
139137 const segment_id = entries[0].segment_id;
140138 var offset = entries[0].offset;
141 try setSegmentOffset(segment_id, offset, bw);
139 try setSegmentOffset(segment_id, offset, writer);
142140
143141 var count: usize = 0;
144142 var skip: u64 = 0;
......@@ -157,7 +155,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
157155 .start => {
158156 if (offset < current_offset) {
159157 const delta = current_offset - offset;
160 try addAddr(delta, bw);
158 try addAddr(delta, writer);
161159 offset += delta;
162160 }
163161 state = .times;
......@@ -177,7 +175,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
177175 offset += skip;
178176 i -= 1;
179177 } else {
180 try rebaseTimes(count, bw);
178 try rebaseTimes(count, writer);
181179 state = .start;
182180 i -= 1;
183181 }
......@@ -186,9 +184,9 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
186184 if (current_offset < offset) {
187185 count -= 1;
188186 if (count == 1) {
189 try rebaseAddAddr(skip, bw);
187 try rebaseAddAddr(skip, writer);
190188 } else {
191 try rebaseTimesSkip(count, skip, bw);
189 try rebaseTimesSkip(count, skip, writer);
192190 }
193191 state = .start;
194192 offset = offset - (@sizeOf(u64) + skip);
......@@ -201,7 +199,7 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
201199 count += 1;
202200 offset += @sizeOf(u64) + skip;
203201 } else {
204 try rebaseTimesSkip(count, skip, bw);
202 try rebaseTimesSkip(count, skip, writer);
205203 state = .start;
206204 i -= 1;
207205 }
......@@ -212,66 +210,68 @@ fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
212210 switch (state) {
213211 .start => unreachable,
214212 .times => {
215 try rebaseTimes(count, bw);
213 try rebaseTimes(count, writer);
216214 },
217215 .times_skip => {
218 try rebaseTimesSkip(count, skip, bw);
216 try rebaseTimesSkip(count, skip, writer);
219217 },
220218 }
221219}
222220
223fn setTypePointer(bw: *Writer) Writer.Error!void {
221fn setTypePointer(writer: anytype) !void {
224222 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)));
226224}
227225
228fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {
226fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
229227 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)));
231 try bw.writeLeb128(offset);
228 try writer.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
229 try std.leb.writeUleb128(writer, offset);
232230}
233231
234fn rebaseAddAddr(addr: u64, bw: *Writer) Writer.Error!void {
232fn rebaseAddAddr(addr: u64, writer: anytype) !void {
235233 log.debug(">>> rebase with add: {x}", .{addr});
236 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
237 try bw.writeLeb128(addr);
234 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
235 try std.leb.writeUleb128(writer, addr);
238236}
239237
240fn rebaseTimes(count: usize, bw: *Writer) Writer.Error!void {
238fn rebaseTimes(count: usize, writer: anytype) !void {
241239 log.debug(">>> rebase with count: {d}", .{count});
242240 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)));
244242 } else {
245 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
246 try bw.writeLeb128(count);
243 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
244 try std.leb.writeUleb128(writer, count);
247245 }
248246}
249247
250fn rebaseTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {
248fn rebaseTimesSkip(count: usize, skip: u64, writer: anytype) !void {
251249 log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip });
252 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
253 try bw.writeLeb128(count);
254 try bw.writeLeb128(skip);
250 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
251 try std.leb.writeUleb128(writer, count);
252 try std.leb.writeUleb128(writer, skip);
255253}
256254
257fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {
255fn addAddr(addr: u64, writer: anytype) !void {
258256 log.debug(">>> add: {x}", .{addr});
259 if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| {
260 if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte(
261 macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | imm_scaled,
262 );
263 } else |_| {}
264 try bw.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);
265 try bw.writeLeb128(addr);
257 if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {
258 const imm = @divExact(addr, @sizeOf(u64));
259 if (imm <= 0xf) {
260 try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)));
261 return;
262 }
263 }
264 try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);
265 try std.leb.writeUleb128(writer, addr);
266266}
267267
268fn done(bw: *Writer) Writer.Error!void {
268fn done(writer: anytype) !void {
269269 log.debug(">>> done", .{});
270 try bw.writeByte(macho.REBASE_OPCODE_DONE);
270 try writer.writeByte(macho.REBASE_OPCODE_DONE);
271271}
272272
273pub fn write(rebase: Rebase, bw: *Writer) Writer.Error!void {
274 try bw.writeAll(rebase.buffer.items);
273pub fn write(rebase: Rebase, writer: anytype) !void {
274 try writer.writeAll(rebase.buffer.items);
275275}
276276
277277test "rebase - no entries" {
src/link/MachO/dyld_info/Trie.zig+37-32
......@@ -31,7 +31,7 @@
3131
3232/// The root node of the trie.
3333root: ?Node.Index = null,
34buffer: []u8 = &.{},
34buffer: std.ArrayListUnmanaged(u8) = .empty,
3535nodes: std.MultiArrayList(Node) = .{},
3636edges: std.ArrayListUnmanaged(Edge) = .empty,
3737
......@@ -123,7 +123,7 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void {
123123
124124 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));
127127}
128128
129129/// Finalizes this trie for writing to a byte stream.
......@@ -138,7 +138,7 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
138138 defer ordered_nodes.deinit();
139139 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);
142142 defer fifo.deinit();
143143
144144 try fifo.writeItem(self.root.?);
......@@ -164,11 +164,9 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
164164 }
165165 }
166166
167 assert(self.buffer.len == 0);
168 self.buffer = try allocator.alloc(u8, size);
169 var bw: Writer = .fixed(self.buffer);
167 try self.buffer.ensureTotalCapacityPrecise(allocator, size);
170168 for (ordered_nodes.items) |node_index| {
171 try self.writeNode(node_index, &bw);
169 try self.writeNode(node_index, self.buffer.writer(allocator));
172170 }
173171}
174172
......@@ -183,17 +181,17 @@ const FinalizeNodeResult = struct {
183181
184182/// Updates offset of this node in the output byte stream.
185183fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult {
186 var buf: [1024]u8 = undefined;
187 var bw: Writer = .discarding(&buf);
184 var stream = std.io.countingWriter(std.io.null_writer);
185 const writer = stream.writer();
188186 const slice = self.nodes.slice();
189187
190188 var node_size: u32 = 0;
191189 if (slice.items(.is_terminal)[node_index]) {
192190 const export_flags = slice.items(.export_flags)[node_index];
193191 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
194 try bw.writeLeb128(export_flags);
195 try bw.writeLeb128(vmaddr_offset);
196 try bw.writeLeb128(bw.count);
192 try leb.writeULEB128(writer, export_flags);
193 try leb.writeULEB128(writer, vmaddr_offset);
194 try leb.writeULEB128(writer, stream.bytes_written);
197195 } else {
198196 node_size += 1; // 0x0 for non-terminal nodes
199197 }
......@@ -203,13 +201,13 @@ fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !Final
203201 const edge = &self.edges.items[edge_index];
204202 const next_node_offset = slice.items(.trie_offset)[edge.node];
205203 node_size += @intCast(edge.label.len + 1);
206 try bw.writeLeb128(next_node_offset);
204 try leb.writeULEB128(writer, next_node_offset);
207205 }
208206
209207 const trie_offset = slice.items(.trie_offset)[node_index];
210208 const updated = offset_in_trie != trie_offset;
211209 slice.items(.trie_offset)[node_index] = offset_in_trie;
212 node_size += @intCast(bw.count);
210 node_size += @intCast(stream.bytes_written);
213211
214212 return .{ .node_size = node_size, .updated = updated };
215213}
......@@ -225,11 +223,12 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {
225223 }
226224 self.nodes.deinit(allocator);
227225 self.edges.deinit(allocator);
228 allocator.free(self.buffer);
226 self.buffer.deinit(allocator);
229227}
230228
231pub fn write(self: Trie, bw: *Writer) Writer.Error!void {
232 try bw.writeAll(self.buffer);
229pub fn write(self: Trie, writer: anytype) !void {
230 if (self.buffer.items.len == 0) return;
231 try writer.writeAll(self.buffer.items);
233232}
234233
235234/// Writes this node to a byte stream.
......@@ -238,7 +237,7 @@ pub fn write(self: Trie, bw: *Writer) Writer.Error!void {
238237/// iterate over `Trie.ordered_nodes` and call this method on each node.
239238/// This is one of the requirements of the MachO.
240239/// 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 {
242241 const slice = self.nodes.slice();
243242 const edges = slice.items(.edges)[node_index];
244243 const is_terminal = slice.items(.is_terminal)[node_index];
......@@ -246,28 +245,36 @@ fn writeNode(self: *Trie, node_index: Node.Index, bw: *Writer) !void {
246245 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
247246
248247 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);
250251 // TODO Implement for special flags.
251252 assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
252253 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 bw.writeLeb128(export_flags);
255 try bw.writeLeb128(vmaddr_offset);
254 try leb.writeULEB128(info_stream.writer(), export_flags);
255 try leb.writeULEB128(info_stream.writer(), vmaddr_offset);
256
256257 // 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]);
258265 } else {
259266 // Non-terminal node is delimited by 0 byte.
260 try bw.writeByte(0);
267 try writer.writeByte(0);
261268 }
262 // Write number of edges (max legal number of edges is 255).
263 try bw.writeByte(@intCast(edges.items.len));
269 // Write number of edges (max legal number of edges is 256).
270 try writer.writeByte(@as(u8, @intCast(edges.items.len)));
264271
265272 for (edges.items) |edge_index| {
266273 const edge = self.edges.items[edge_index];
267274 // Write edge label and offset to next node in trie.
268 try bw.writeAll(edge.label);
269 try bw.writeByte(0);
270 try bw.writeLeb128(slice.items(.trie_offset)[edge.node]);
275 try writer.writeAll(edge.label);
276 try writer.writeByte(0);
277 try leb.writeULEB128(writer, slice.items(.trie_offset)[edge.node]);
271278 }
272279}
273280
......@@ -407,10 +414,8 @@ const macho = std.macho;
407414const mem = std.mem;
408415const std = @import("std");
409416const testing = std.testing;
410const Writer = std.io.Writer;
411
412417const trace = @import("../../../tracy.zig").trace;
413const DeprecatedLinearFifo = @import("../../../deprecated.zig").LinearFifo;
418
414419const Allocator = mem.Allocator;
415420const MachO = @import("../../MachO.zig");
416421const Trie = @This();
src/link/MachO/dyld_info/bind.zig+187-155
......@@ -1,7 +1,7 @@
11pub const Entry = struct {
22 target: MachO.Ref,
33 offset: u64,
4 segment_id: u4,
4 segment_id: u8,
55 addend: i64,
66
77 pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool {
......@@ -20,12 +20,14 @@ pub const Bind = struct {
2020 entries: std.ArrayListUnmanaged(Entry) = .empty,
2121 buffer: std.ArrayListUnmanaged(u8) = .empty,
2222
23 pub fn deinit(bind: *Bind, gpa: Allocator) void {
24 bind.entries.deinit(gpa);
25 bind.buffer.deinit(gpa);
23 const Self = @This();
24
25 pub fn deinit(self: *Self, gpa: Allocator) void {
26 self.entries.deinit(gpa);
27 self.buffer.deinit(gpa);
2628 }
2729
28 pub fn updateSize(bind: *Bind, macho_file: *MachO) !void {
30 pub fn updateSize(self: *Self, macho_file: *MachO) !void {
2931 const tracy = trace(@src());
3032 defer tracy.end();
3133
......@@ -54,12 +56,15 @@ pub const Bind = struct {
5456 const addend = rel.addend + rel.getRelocAddend(cpu_arch);
5557 const sym = rel.getTargetSymbol(atom.*, macho_file);
5658 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{
5860 .target = rel.getTargetSymbolRef(atom.*, macho_file),
5961 .offset = atom_addr + rel_offset - seg.vmaddr,
6062 .segment_id = seg_id,
6163 .addend = addend,
6264 };
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 }
6368 }
6469 }
6570 }
......@@ -70,12 +75,15 @@ pub const Bind = struct {
7075 for (macho_file.got.symbols.items, 0..) |ref, idx| {
7176 const sym = ref.getSymbol(macho_file).?;
7277 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{
7479 .target = ref,
7580 .offset = addr - seg.vmaddr,
7681 .segment_id = seg_id,
7782 .addend = 0,
7883 };
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 }
7987 }
8088 }
8189
......@@ -86,12 +94,15 @@ pub const Bind = struct {
8694 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
8795 const sym = ref.getSymbol(macho_file).?;
8896 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{
9098 .target = ref,
9199 .offset = addr - seg.vmaddr,
92100 .segment_id = seg_id,
93101 .addend = 0,
94102 };
103 if (sym.flags.import and sym.flags.weak) {
104 try self.entries.append(gpa, bind_entry);
105 }
95106 }
96107 }
97108
......@@ -102,48 +113,49 @@ pub const Bind = struct {
102113 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
103114 const sym = ref.getSymbol(macho_file).?;
104115 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{
106117 .target = ref,
107118 .offset = addr - seg.vmaddr,
108119 .segment_id = seg_id,
109120 .addend = 0,
110121 };
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 }
111125 }
112126 }
113127
114 try bind.finalize(gpa, macho_file);
115 macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
128 try self.finalize(gpa, macho_file);
129 macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
116130 }
117131
118 fn finalize(bind: *Bind, gpa: Allocator, ctx: *MachO) !void {
119 if (bind.entries.items.len == 0) return;
132 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
133 if (self.entries.items.len == 0) return;
120134
121 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
122 const bw = &aw.writer;
123 defer bind.buffer = aw.toArrayList();
135 const writer = self.buffer.writer(gpa);
124136
125137 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
129141 var start: usize = 0;
130142 var seg_id: ?u8 = null;
131 for (bind.entries.items, 0..) |entry, i| {
143 for (self.entries.items, 0..) |entry, i| {
132144 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);
134146 seg_id = entry.segment_id;
135147 start = i;
136148 }
137149
138 try finalizeSegment(bind.entries.items[start..], ctx, bw);
139 try done(bw);
150 try finalizeSegment(self.entries.items[start..], ctx, writer);
151 try done(writer);
140152 }
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 {
143155 if (entries.len == 0) return;
144156
145157 const seg_id = entries[0].segment_id;
146 try setSegmentOffset(seg_id, 0, bw);
158 try setSegmentOffset(seg_id, 0, writer);
147159
148160 var offset: u64 = 0;
149161 var addend: i64 = 0;
......@@ -163,15 +175,15 @@ pub const Bind = struct {
163175 if (target == null or !target.?.eql(current.target)) {
164176 switch (state) {
165177 .start => {},
166 .bind_single => try doBind(bw),
167 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
178 .bind_single => try doBind(writer),
179 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
168180 }
169181 state = .start;
170182 target = current.target;
171183
172184 const sym = current.target.getSymbol(ctx).?;
173185 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;
175187 const ordinal: i16 = ord: {
176188 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
177189 if (sym.flags.import) {
......@@ -183,13 +195,13 @@ pub const Bind = struct {
183195 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
184196 };
185197
186 try setSymbol(name, flags, bw);
187 try setTypePointer(bw);
188 try setDylibOrdinal(ordinal, bw);
198 try setSymbol(name, flags, writer);
199 try setTypePointer(writer);
200 try setDylibOrdinal(ordinal, writer);
189201
190202 if (current.addend != addend) {
191203 addend = current.addend;
192 try setAddend(addend, bw);
204 try setAddend(addend, writer);
193205 }
194206 }
195207
......@@ -198,11 +210,11 @@ pub const Bind = struct {
198210 switch (state) {
199211 .start => {
200212 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);
202214 offset = offset - (offset - current.offset);
203215 } else if (current.offset > offset) {
204216 const delta = current.offset - offset;
205 try addAddr(delta, bw);
217 try addAddr(delta, writer);
206218 offset += delta;
207219 }
208220 state = .bind_single;
......@@ -211,7 +223,7 @@ pub const Bind = struct {
211223 },
212224 .bind_single => {
213225 if (current.offset == offset) {
214 try doBind(bw);
226 try doBind(writer);
215227 state = .start;
216228 } else if (current.offset > offset) {
217229 const delta = current.offset - offset;
......@@ -225,9 +237,9 @@ pub const Bind = struct {
225237 if (current.offset < offset) {
226238 count -= 1;
227239 if (count == 1) {
228 try doBindAddAddr(skip, bw);
240 try doBindAddAddr(skip, writer);
229241 } else {
230 try doBindTimesSkip(count, skip, bw);
242 try doBindTimesSkip(count, skip, writer);
231243 }
232244 state = .start;
233245 offset = offset - (@sizeOf(u64) + skip);
......@@ -236,7 +248,7 @@ pub const Bind = struct {
236248 count += 1;
237249 offset += @sizeOf(u64) + skip;
238250 } else {
239 try doBindTimesSkip(count, skip, bw);
251 try doBindTimesSkip(count, skip, writer);
240252 state = .start;
241253 i -= 1;
242254 }
......@@ -246,13 +258,13 @@ pub const Bind = struct {
246258
247259 switch (state) {
248260 .start => unreachable,
249 .bind_single => try doBind(bw),
250 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
261 .bind_single => try doBind(writer),
262 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
251263 }
252264 }
253265
254 pub fn write(bind: Bind, bw: *Writer) Writer.Error!void {
255 try bw.writeAll(bind.buffer.items);
266 pub fn write(self: Self, writer: anytype) !void {
267 try writer.writeAll(self.buffer.items);
256268 }
257269};
258270
......@@ -260,12 +272,14 @@ pub const WeakBind = struct {
260272 entries: std.ArrayListUnmanaged(Entry) = .empty,
261273 buffer: std.ArrayListUnmanaged(u8) = .empty,
262274
263 pub fn deinit(bind: *WeakBind, gpa: Allocator) void {
264 bind.entries.deinit(gpa);
265 bind.buffer.deinit(gpa);
275 const Self = @This();
276
277 pub fn deinit(self: *Self, gpa: Allocator) void {
278 self.entries.deinit(gpa);
279 self.buffer.deinit(gpa);
266280 }
267281
268 pub fn updateSize(bind: *WeakBind, macho_file: *MachO) !void {
282 pub fn updateSize(self: *Self, macho_file: *MachO) !void {
269283 const tracy = trace(@src());
270284 defer tracy.end();
271285
......@@ -294,12 +308,15 @@ pub const WeakBind = struct {
294308 const addend = rel.addend + rel.getRelocAddend(cpu_arch);
295309 const sym = rel.getTargetSymbol(atom.*, macho_file);
296310 if (sym.isTlvInit(macho_file)) continue;
297 if (!sym.isLocal() and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
311 const entry = Entry{
298312 .target = rel.getTargetSymbolRef(atom.*, macho_file),
299313 .offset = atom_addr + rel_offset - seg.vmaddr,
300314 .segment_id = seg_id,
301315 .addend = addend,
302316 };
317 if (!sym.isLocal() and sym.flags.weak) {
318 try self.entries.append(gpa, entry);
319 }
303320 }
304321 }
305322 }
......@@ -310,12 +327,15 @@ pub const WeakBind = struct {
310327 for (macho_file.got.symbols.items, 0..) |ref, idx| {
311328 const sym = ref.getSymbol(macho_file).?;
312329 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
313 if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
330 const entry = Entry{
314331 .target = ref,
315332 .offset = addr - seg.vmaddr,
316333 .segment_id = seg_id,
317334 .addend = 0,
318335 };
336 if (sym.flags.weak) {
337 try self.entries.append(gpa, entry);
338 }
319339 }
320340 }
321341
......@@ -327,12 +347,15 @@ pub const WeakBind = struct {
327347 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
328348 const sym = ref.getSymbol(macho_file).?;
329349 const addr = sect.addr + idx * @sizeOf(u64);
330 if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
350 const bind_entry = Entry{
331351 .target = ref,
332352 .offset = addr - seg.vmaddr,
333353 .segment_id = seg_id,
334354 .addend = 0,
335355 };
356 if (sym.flags.weak) {
357 try self.entries.append(gpa, bind_entry);
358 }
336359 }
337360 }
338361
......@@ -343,48 +366,49 @@ pub const WeakBind = struct {
343366 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
344367 const sym = ref.getSymbol(macho_file).?;
345368 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{
347370 .target = ref,
348371 .offset = addr - seg.vmaddr,
349372 .segment_id = seg_id,
350373 .addend = 0,
351374 };
375 if (sym.flags.weak) {
376 try self.entries.append(gpa, entry);
377 }
352378 }
353379 }
354380
355 try bind.finalize(gpa, macho_file);
356 macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
381 try self.finalize(gpa, macho_file);
382 macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
357383 }
358384
359 fn finalize(bind: *WeakBind, gpa: Allocator, ctx: *MachO) !void {
360 if (bind.entries.items.len == 0) return;
385 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
386 if (self.entries.items.len == 0) return;
361387
362 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
363 const bw = &aw.writer;
364 defer bind.buffer = aw.toArrayList();
388 const writer = self.buffer.writer(gpa);
365389
366390 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
370394 var start: usize = 0;
371395 var seg_id: ?u8 = null;
372 for (bind.entries.items, 0..) |entry, i| {
396 for (self.entries.items, 0..) |entry, i| {
373397 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);
375399 seg_id = entry.segment_id;
376400 start = i;
377401 }
378402
379 try finalizeSegment(bind.entries.items[start..], ctx, bw);
380 try done(bw);
403 try finalizeSegment(self.entries.items[start..], ctx, writer);
404 try done(writer);
381405 }
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 {
384408 if (entries.len == 0) return;
385409
386410 const seg_id = entries[0].segment_id;
387 try setSegmentOffset(seg_id, 0, bw);
411 try setSegmentOffset(seg_id, 0, writer);
388412
389413 var offset: u64 = 0;
390414 var addend: i64 = 0;
......@@ -404,8 +428,8 @@ pub const WeakBind = struct {
404428 if (target == null or !target.?.eql(current.target)) {
405429 switch (state) {
406430 .start => {},
407 .bind_single => try doBind(bw),
408 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
431 .bind_single => try doBind(writer),
432 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
409433 }
410434 state = .start;
411435 target = current.target;
......@@ -414,12 +438,12 @@ pub const WeakBind = struct {
414438 const name = sym.getName(ctx);
415439 const flags: u8 = 0; // TODO NON_WEAK_DEFINITION
416440
417 try setSymbol(name, flags, bw);
418 try setTypePointer(bw);
441 try setSymbol(name, flags, writer);
442 try setTypePointer(writer);
419443
420444 if (current.addend != addend) {
421445 addend = current.addend;
422 try setAddend(addend, bw);
446 try setAddend(addend, writer);
423447 }
424448 }
425449
......@@ -428,11 +452,11 @@ pub const WeakBind = struct {
428452 switch (state) {
429453 .start => {
430454 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);
432456 offset = offset - (offset - current.offset);
433457 } else if (current.offset > offset) {
434458 const delta = current.offset - offset;
435 try addAddr(delta, bw);
459 try addAddr(delta, writer);
436460 offset += delta;
437461 }
438462 state = .bind_single;
......@@ -441,7 +465,7 @@ pub const WeakBind = struct {
441465 },
442466 .bind_single => {
443467 if (current.offset == offset) {
444 try doBind(bw);
468 try doBind(writer);
445469 state = .start;
446470 } else if (current.offset > offset) {
447471 const delta = current.offset - offset;
......@@ -455,9 +479,9 @@ pub const WeakBind = struct {
455479 if (current.offset < offset) {
456480 count -= 1;
457481 if (count == 1) {
458 try doBindAddAddr(skip, bw);
482 try doBindAddAddr(skip, writer);
459483 } else {
460 try doBindTimesSkip(count, skip, bw);
484 try doBindTimesSkip(count, skip, writer);
461485 }
462486 state = .start;
463487 offset = offset - (@sizeOf(u64) + skip);
......@@ -466,7 +490,7 @@ pub const WeakBind = struct {
466490 count += 1;
467491 offset += @sizeOf(u64) + skip;
468492 } else {
469 try doBindTimesSkip(count, skip, bw);
493 try doBindTimesSkip(count, skip, writer);
470494 state = .start;
471495 i -= 1;
472496 }
......@@ -476,13 +500,13 @@ pub const WeakBind = struct {
476500
477501 switch (state) {
478502 .start => unreachable,
479 .bind_single => try doBind(bw),
480 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
503 .bind_single => try doBind(writer),
504 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
481505 }
482506 }
483507
484 pub fn write(bind: WeakBind, bw: *Writer) Writer.Error!void {
485 try bw.writeAll(bind.buffer.items);
508 pub fn write(self: Self, writer: anytype) !void {
509 try writer.writeAll(self.buffer.items);
486510 }
487511};
488512
......@@ -491,13 +515,15 @@ pub const LazyBind = struct {
491515 buffer: std.ArrayListUnmanaged(u8) = .empty,
492516 offsets: std.ArrayListUnmanaged(u32) = .empty,
493517
494 pub fn deinit(bind: *LazyBind, gpa: Allocator) void {
495 bind.entries.deinit(gpa);
496 bind.buffer.deinit(gpa);
497 bind.offsets.deinit(gpa);
518 const Self = @This();
519
520 pub fn deinit(self: *Self, gpa: Allocator) void {
521 self.entries.deinit(gpa);
522 self.buffer.deinit(gpa);
523 self.offsets.deinit(gpa);
498524 }
499525
500 pub fn updateSize(bind: *LazyBind, macho_file: *MachO) !void {
526 pub fn updateSize(self: *Self, macho_file: *MachO) !void {
501527 const tracy = trace(@src());
502528 defer tracy.end();
503529
......@@ -511,35 +537,36 @@ pub const LazyBind = struct {
511537 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
512538 const sym = ref.getSymbol(macho_file).?;
513539 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{
515541 .target = ref,
516542 .offset = addr - seg.vmaddr,
517543 .segment_id = seg_id,
518544 .addend = 0,
519545 };
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 }
520549 }
521550
522 try bind.finalize(gpa, macho_file);
523 macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
551 try self.finalize(gpa, macho_file);
552 macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));
524553 }
525554
526 fn finalize(bind: *LazyBind, gpa: Allocator, ctx: *MachO) !void {
527 try bind.offsets.ensureTotalCapacityPrecise(gpa, bind.entries.items.len);
555 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
556 try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);
528557
529 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
530 const bw = &aw.writer;
531 defer bind.buffer = aw.toArrayList();
558 const writer = self.buffer.writer(gpa);
532559
533560 log.debug("lazy bind opcodes", .{});
534561
535562 var addend: i64 = 0;
536563
537 for (bind.entries.items) |entry| {
538 bind.offsets.appendAssumeCapacity(@intCast(bind.buffer.items.len));
564 for (self.entries.items) |entry| {
565 self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len));
539566
540567 const sym = entry.target.getSymbol(ctx).?;
541568 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;
543570 const ordinal: i16 = ord: {
544571 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
545572 if (sym.flags.import) {
......@@ -551,116 +578,121 @@ pub const LazyBind = struct {
551578 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
552579 };
553580
554 try setSegmentOffset(entry.segment_id, entry.offset, bw);
555 try setSymbol(name, flags, bw);
556 try setDylibOrdinal(ordinal, bw);
581 try setSegmentOffset(entry.segment_id, entry.offset, writer);
582 try setSymbol(name, flags, writer);
583 try setDylibOrdinal(ordinal, writer);
557584
558585 if (entry.addend != addend) {
559 try setAddend(entry.addend, bw);
586 try setAddend(entry.addend, writer);
560587 addend = entry.addend;
561588 }
562589
563 try doBind(bw);
564 try done(bw);
590 try doBind(writer);
591 try done(writer);
565592 }
566593 }
567594
568 pub fn write(bind: LazyBind, bw: *Writer) Writer.Error!void {
569 try bw.writeAll(bind.buffer.items);
595 pub fn write(self: Self, writer: anytype) !void {
596 try writer.writeAll(self.buffer.items);
570597 }
571598};
572599
573fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {
600fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
574601 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);
576 try bw.writeLeb128(offset);
602 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
603 try std.leb.writeUleb128(writer, offset);
577604}
578605
579fn setSymbol(name: []const u8, flags: u4, bw: *Writer) Writer.Error!void {
606fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void {
580607 log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });
581 try bw.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags);
582 try bw.writeAll(name);
583 try bw.writeByte(0);
608 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags)));
609 try writer.writeAll(name);
610 try writer.writeByte(0);
584611}
585612
586fn setTypePointer(bw: *Writer) Writer.Error!void {
613fn setTypePointer(writer: anytype) !void {
587614 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)));
589616}
590617
591fn setDylibOrdinal(ordinal: i16, bw: *Writer) Writer.Error!void {
592 switch (ordinal) {
593 else => unreachable, // Invalid dylib special binding
594 macho.BIND_SPECIAL_DYLIB_SELF,
595 macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE,
596 macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP,
597 => {
598 log.debug(">>> set dylib special: {d}", .{ordinal});
599 try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @bitCast(@as(i4, @intCast(ordinal)))));
600 },
601 1...std.math.maxInt(i16) => {
602 log.debug(">>> set dylib ordinal: {d}", .{ordinal});
603 if (std.math.cast(u4, ordinal)) |imm| {
604 try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | imm);
605 } else {
606 try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
607 try bw.writeUleb128(ordinal);
608 }
609 },
618fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {
619 if (ordinal <= 0) {
620 switch (ordinal) {
621 macho.BIND_SPECIAL_DYLIB_SELF,
622 macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE,
623 macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP,
624 => {},
625 else => unreachable, // Invalid dylib special binding
626 }
627 log.debug(">>> set dylib special: {d}", .{ordinal});
628 const cast = @as(u16, @bitCast(ordinal));
629 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @truncate(cast)));
630 } else {
631 const cast = @as(u16, @bitCast(ordinal));
632 log.debug(">>> set dylib ordinal: {d}", .{ordinal});
633 if (cast <= 0xf) {
634 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @as(u4, @truncate(cast)));
635 } else {
636 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
637 try std.leb.writeUleb128(writer, cast);
638 }
610639 }
611640}
612641
613fn setAddend(addend: i64, bw: *Writer) Writer.Error!void {
642fn setAddend(addend: i64, writer: anytype) !void {
614643 log.debug(">>> set addend: {x}", .{addend});
615 try bw.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
616 try bw.writeLeb128(addend);
644 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
645 try std.leb.writeIleb128(writer, addend);
617646}
618647
619fn doBind(bw: *Writer) Writer.Error!void {
648fn doBind(writer: anytype) !void {
620649 log.debug(">>> bind", .{});
621 try bw.writeByte(macho.BIND_OPCODE_DO_BIND);
650 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
622651}
623652
624fn doBindAddAddr(addr: u64, bw: *Writer) Writer.Error!void {
653fn doBindAddAddr(addr: u64, writer: anytype) !void {
625654 log.debug(">>> bind with add: {x}", .{addr});
626 if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| {
627 if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte(
628 macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | imm_scaled,
629 );
630 } else |_| {}
631 try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
632 try bw.writeLeb128(addr);
655 if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {
656 const imm = @divExact(addr, @sizeOf(u64));
657 if (imm <= 0xf) {
658 try writer.writeByte(
659 macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)),
660 );
661 return;
662 }
663 }
664 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
665 try std.leb.writeUleb128(writer, addr);
633666}
634667
635fn doBindTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {
668fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void {
636669 log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });
637 try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
638 try bw.writeLeb128(count);
639 try bw.writeLeb128(skip);
670 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
671 try std.leb.writeUleb128(writer, count);
672 try std.leb.writeUleb128(writer, skip);
640673}
641674
642fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {
675fn addAddr(addr: u64, writer: anytype) !void {
643676 log.debug(">>> add: {x}", .{addr});
644 try bw.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
645 try bw.writeLeb128(addr);
677 try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
678 try std.leb.writeUleb128(writer, addr);
646679}
647680
648fn done(bw: *Writer) Writer.Error!void {
681fn done(writer: anytype) !void {
649682 log.debug(">>> done", .{});
650 try bw.writeByte(macho.BIND_OPCODE_DONE);
683 try writer.writeByte(macho.BIND_OPCODE_DONE);
651684}
652685
653const std = @import("std");
654686const assert = std.debug.assert;
655687const leb = std.leb;
656688const log = std.log.scoped(.link_dyld_info);
657689const macho = std.macho;
658690const mem = std.mem;
659691const testing = std.testing;
660const Allocator = std.mem.Allocator;
661const Writer = std.io.Writer;
662
663692const trace = @import("../../../tracy.zig").trace;
693const std = @import("std");
694
695const Allocator = mem.Allocator;
664696const File = @import("../file.zig").File;
665697const MachO = @import("../../MachO.zig");
666698const Symbol = @import("../Symbol.zig");
src/link/MachO/eh_frame.zig+69-44
......@@ -12,33 +12,36 @@ pub const Cie = struct {
1212 const tracy = trace(@src());
1313 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);
1918 if (aug[0] != 'z') return; // TODO should we error out?
2019
21 _ = try r.takeLeb128(u64); // code alignment factor
22 _ = try r.takeLeb128(u64); // data alignment factor
23 _ = try r.takeLeb128(u64); // return address register
24 _ = try r.takeLeb128(u64); // augmentation data length
20 var stream = std.io.fixedBufferStream(data[9 + aug.len + 1 ..]);
21 var creader = std.io.countingReader(stream.reader());
22 const reader = creader.reader();
23
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
2629 for (aug[1..]) |ch| switch (ch) {
2730 'R' => {
28 const enc = try r.takeByte();
31 const enc = try reader.readByte();
2932 if (enc != DW_EH_PE.pcrel | DW_EH_PE.absptr) {
3033 @panic("unexpected pointer encoding"); // TODO error
3134 }
3235 },
3336 'P' => {
34 const enc = try r.takeByte();
37 const enc = try reader.readByte();
3538 if (enc != DW_EH_PE.pcrel | DW_EH_PE.indirect | DW_EH_PE.sdata4) {
3639 @panic("unexpected personality pointer encoding"); // TODO error
3740 }
38 _ = try r.takeInt(u32, .little); // personality pointer
41 _ = try reader.readInt(u32, .little); // personality pointer
3942 },
4043 'L' => {
41 const enc = try r.takeByte();
44 const enc = try reader.readByte();
4245 switch (enc & DW_EH_PE.type_mask) {
4346 DW_EH_PE.sdata4 => cie.lsda_size = .p32,
4447 DW_EH_PE.absptr => cie.lsda_size = .p64,
......@@ -125,16 +128,12 @@ pub const Fde = struct {
125128 const tracy = trace(@src());
126129 defer tracy.end();
127130
131 const data = fde.getData(macho_file);
128132 const object = fde.getObject(macho_file);
129133 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
137135 // Parse target atom index
136 const pc_begin = std.mem.readInt(i64, data[8..][0..8], .little);
138137 const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
139138 fde.atom = object.findAtom(taddr) orelse {
140139 try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
......@@ -146,6 +145,7 @@ pub const Fde = struct {
146145 fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
147146
148147 // Associate with a CIE
148 const cie_ptr = std.mem.readInt(u32, data[4..8], .little);
149149 const cie_offset = fde.offset + 4 - cie_ptr;
150150 const cie_index = for (object.cies.items, 0..) |cie, cie_index| {
151151 if (cie.offset == cie_offset) break @as(Cie.Index, @intCast(cie_index));
......@@ -163,12 +163,14 @@ pub const Fde = struct {
163163
164164 // Parse LSDA atom index if any
165165 if (cie.lsda_size) |lsda_size| {
166 try br.discard(8);
167 _ = try br.takeLeb128(u64); // augmentation length
168 fde.lsda_ptr_offset = @intCast(br.seek);
166 var stream = std.io.fixedBufferStream(data[24..]);
167 var creader = std.io.countingReader(stream.reader());
168 const reader = creader.reader();
169 _ = try leb.readUleb128(u64, reader); // augmentation length
170 fde.lsda_ptr_offset = @intCast(creader.bytes_read + 24);
169171 const lsda_ptr = switch (lsda_size) {
170 .p32 => try br.takeInt(i32, .little),
171 .p64 => try br.takeInt(i64, .little),
172 .p32 => try reader.readInt(i32, .little),
173 .p64 => try reader.readInt(i64, .little),
172174 };
173175 const lsda_addr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + fde.lsda_ptr_offset)) + lsda_ptr);
174176 fde.lsda = object.findAtom(lsda_addr) orelse {
......@@ -209,35 +211,56 @@ pub const Fde = struct {
209211 return fde.getObject(macho_file).getAtom(fde.lsda);
210212 }
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) {
213228 return .{ .data = .{
214229 .fde = fde,
215230 .macho_file = macho_file,
216231 } };
217232 }
218233
219 const Format = struct {
234 const FormatContext = struct {
220235 fde: Fde,
221236 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 }
234237 };
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
236258 pub const Index = u32;
237259};
238260
239261pub const Iterator = struct {
240 reader: *std.io.Reader,
262 data: []const u8,
263 pos: u32 = 0,
241264
242265 pub const Record = struct {
243266 tag: enum { fde, cie },
......@@ -246,19 +269,21 @@ pub const Iterator = struct {
246269 };
247270
248271 pub fn next(it: *Iterator) !?Record {
249 const r = it.reader;
250 if (r.seek >= r.storageBuffer().len) return null;
272 if (it.pos >= it.data.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);
253278 if (size == 0xFFFFFFFF) @panic("DWARF CFI is 32bit on macOS");
254279
255 const id = try r.takeInt(u32, .little);
256 const record: Record = .{
280 const id = try reader.readInt(u32, .little);
281 const record = Record{
257282 .tag = if (id == 0) .cie else .fde,
258 .offset = @intCast(r.seek),
283 .offset = it.pos,
259284 .size = size,
260285 };
261 try r.discard(size);
286 it.pos += size + 4;
262287
263288 return record;
264289 }
src/link/MachO/file.zig+3-3
......@@ -321,11 +321,11 @@ pub const File = union(enum) {
321321 };
322322 }
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 {
325325 return switch (file) {
326326 .dylib, .internal => unreachable,
327 .zig_object => |x| x.writeAr(bw, ar_format),
328 .object => |x| x.writeAr(bw, ar_format, macho_file),
327 .zig_object => |x| x.writeAr(ar_format, writer),
328 .object => |x| x.writeAr(ar_format, macho_file, writer),
329329 };
330330 }
331331
src/link/MachO/load_commands.zig+30-21
......@@ -181,20 +181,23 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
181181 return offset;
182182}
183183
184pub fn writeDylinkerLC(bw: *Writer) Writer.Error!void {
184pub fn writeDylinkerLC(writer: anytype) !void {
185185 const name_len = mem.sliceTo(default_dyld_path, 0).len;
186186 const cmdsize = @as(u32, @intCast(mem.alignForward(
187187 u64,
188188 @sizeOf(macho.dylinker_command) + name_len,
189189 @sizeOf(u64),
190190 )));
191 try bw.writeStruct(macho.dylinker_command{
191 try writer.writeStruct(macho.dylinker_command{
192192 .cmd = .LOAD_DYLINKER,
193193 .cmdsize = cmdsize,
194194 .name = @sizeOf(macho.dylinker_command),
195195 });
196 try bw.writeAll(mem.sliceTo(default_dyld_path, 0));
197 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylinker_command) - name_len);
196 try writer.writeAll(mem.sliceTo(default_dyld_path, 0));
197 const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;
198 if (padding > 0) {
199 try writer.writeByteNTimes(0, padding);
200 }
198201}
199202
200203const WriteDylibLCCtx = struct {
......@@ -205,14 +208,14 @@ const WriteDylibLCCtx = struct {
205208 compatibility_version: u32 = 0x10000,
206209};
207210
208pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {
211pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
209212 const name_len = ctx.name.len + 1;
210 const cmdsize: u32 = @intCast(mem.alignForward(
213 const cmdsize = @as(u32, @intCast(mem.alignForward(
211214 u64,
212215 @sizeOf(macho.dylib_command) + name_len,
213216 @sizeOf(u64),
214 ));
215 try bw.writeStruct(macho.dylib_command{
217 )));
218 try writer.writeStruct(macho.dylib_command{
216219 .cmd = ctx.cmd,
217220 .cmdsize = cmdsize,
218221 .dylib = .{
......@@ -222,9 +225,12 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {
222225 .compatibility_version = ctx.compatibility_version,
223226 },
224227 });
225 try bw.writeAll(ctx.name);
226 try bw.writeByte(0);
227 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylib_command) - name_len);
228 try writer.writeAll(ctx.name);
229 try writer.writeByte(0);
230 const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;
231 if (padding > 0) {
232 try writer.writeByteNTimes(0, padding);
233 }
228234}
229235
230236pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
......@@ -253,23 +259,26 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
253259 }, writer);
254260}
255261
256pub fn writeRpathLC(bw: *Writer, rpath: []const u8) !void {
262pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {
257263 const rpath_len = rpath.len + 1;
258264 const cmdsize = @as(u32, @intCast(mem.alignForward(
259265 u64,
260266 @sizeOf(macho.rpath_command) + rpath_len,
261267 @sizeOf(u64),
262268 )));
263 try bw.writeStruct(macho.rpath_command{
269 try writer.writeStruct(macho.rpath_command{
264270 .cmdsize = cmdsize,
265271 .path = @sizeOf(macho.rpath_command),
266272 });
267 try bw.writeAll(rpath);
268 try bw.writeByte(0);
269 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.rpath_command) - rpath_len);
273 try writer.writeAll(rpath);
274 try writer.writeByte(0);
275 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
276 if (padding > 0) {
277 try writer.writeByteNTimes(0, padding);
278 }
270279}
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 {
273282 const cmd: macho.LC = switch (platform.os_tag) {
274283 .macos => .VERSION_MIN_MACOSX,
275284 .ios => .VERSION_MIN_IPHONEOS,
......@@ -277,7 +286,7 @@ pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?st
277286 .watchos => .VERSION_MIN_WATCHOS,
278287 else => unreachable,
279288 };
280 try bw.writeAll(mem.asBytes(&macho.version_min_command{
289 try writer.writeAll(mem.asBytes(&macho.version_min_command{
281290 .cmd = cmd,
282291 .version = platform.toAppleVersion(),
283292 .sdk = if (sdk_version) |ver|
......@@ -287,9 +296,9 @@ pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?st
287296 }));
288297}
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 {
291300 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{
293302 .cmdsize = cmdsize,
294303 .platform = platform.toApplePlatform(),
295304 .minos = platform.toAppleVersion(),
......@@ -299,7 +308,7 @@ pub fn writeBuildVersionLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?
299308 platform.toAppleVersion(),
300309 .ntools = 1,
301310 });
302 try bw.writeAll(mem.asBytes(&macho.build_tool_version{
311 try writer.writeAll(mem.asBytes(&macho.build_tool_version{
303312 .tool = .ZIG,
304313 .version = 0x0,
305314 }));
src/link/MachO/relocatable.zig+52-24
......@@ -202,30 +202,38 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
202202 };
203203
204204 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)});
206206 }
207207
208 var bw: Writer = .fixed(try gpa.alloc(u8, total_size));
209 defer gpa.free(bw.buffer);
208 var buffer = std.ArrayList(u8).init(gpa);
209 defer buffer.deinit();
210 try buffer.ensureTotalCapacityPrecise(total_size);
211 const writer = buffer.writer();
210212
211213 // Write magic
212 bw.writeAll(Archive.ARMAG) catch unreachable;
214 try writer.writeAll(Archive.ARMAG);
213215
214216 // Write symtab
215 ar_symtab.write(&bw, format, macho_file) catch |err| {
216 return diags.fail("failed to write archive symbol table: {s}", .{@errorName(err)});
217 ar_symtab.write(format, macho_file, writer) catch |err| switch (err) {
218 error.OutOfMemory => return error.OutOfMemory,
219 else => |e| return diags.fail("failed to write archive symbol table: {s}", .{@errorName(e)}),
217220 };
218221
219222 // Write object files
220223 for (files.items) |index| {
221 bw.splatByteAll(0, mem.alignForward(usize, bw.end, 2) - bw.end) catch unreachable;
222 macho_file.getFile(index).?.writeAr(&bw, format, macho_file) catch |err|
224 const aligned = mem.alignForward(usize, buffer.items.len, 2);
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|
223230 return diags.fail("failed to write archive: {s}", .{@errorName(err)});
224231 }
225232
226 assert(bw.end == bw.buffer.len);
227 try macho_file.setEndPos(bw.end);
228 try macho_file.pwriteAll(bw.buffer, 0);
233 assert(buffer.items.len == total_size);
234
235 try macho_file.setEndPos(total_size);
236 try macho_file.pwriteAll(buffer.items, 0);
229237
230238 if (diags.hasErrors()) return error.LinkFailure;
231239}
......@@ -664,7 +672,7 @@ fn writeCompactUnwindWorker(macho_file: *MachO, object: *Object) void {
664672 diags.addError("failed to write '__LD,__eh_frame' section: {s}", .{@errorName(err)});
665673}
666674
667fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {
675fn writeSectionsToFile(macho_file: *MachO) !void {
668676 const tracy = trace(@src());
669677 defer tracy.end();
670678
......@@ -681,8 +689,12 @@ fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {
681689
682690fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } {
683691 const gpa = macho_file.base.comp.gpa;
684 var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeObject(macho_file)));
685 defer gpa.free(bw.buffer);
692 const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file);
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
687699 var ncmds: usize = 0;
688700
......@@ -690,31 +702,47 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
690702 {
691703 assert(macho_file.segments.items.len == 1);
692704 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 };
694708 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 };
696712 }
697713 ncmds += 1;
698714 }
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 };
701719 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 };
703723 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 };
705727 ncmds += 1;
706728
707729 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 };
709733 ncmds += 1;
710734 } 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 };
712738 ncmds += 1;
713739 }
714740
715 assert(bw.end == bw.buffer.len);
716 try macho_file.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
717 return .{ ncmds, bw.end };
741 assert(stream.pos == needed_size);
742
743 try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
744
745 return .{ ncmds, buffer.len };
718746}
719747
720748fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
src/link/MachO/synthetic.zig+54-54
......@@ -27,13 +27,13 @@ pub const GotSection = struct {
2727 return got.symbols.items.len * @sizeOf(u64);
2828 }
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 {
3131 const tracy = trace(@src());
3232 defer tracy.end();
3333 for (got.symbols.items) |ref| {
3434 const sym = ref.getSymbol(macho_file).?;
3535 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);
3737 }
3838 }
3939
......@@ -89,7 +89,7 @@ pub const StubsSection = struct {
8989 return stubs.symbols.items.len * header.reserved2;
9090 }
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 {
9393 const tracy = trace(@src());
9494 defer tracy.end();
9595 const cpu_arch = macho_file.getTarget().cpu.arch;
......@@ -101,20 +101,20 @@ pub const StubsSection = struct {
101101 const target = laptr_sect.addr + idx * @sizeOf(u64);
102102 switch (cpu_arch) {
103103 .x86_64 => {
104 try bw.writeAll(&.{ 0xff, 0x25 });
105 try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little);
104 try writer.writeAll(&.{ 0xff, 0x25 });
105 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
106106 },
107107 .aarch64 => {
108108 // TODO relax if possible
109109 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);
111111 const off = try math.divExact(u12, @truncate(target), 8);
112 try bw.writeInt(
112 try writer.writeInt(
113113 u32,
114114 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
115115 .little,
116116 );
117 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
117 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
118118 },
119119 else => unreachable,
120120 }
......@@ -175,11 +175,11 @@ pub const StubsHelperSection = struct {
175175 return s;
176176 }
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 {
179179 const tracy = trace(@src());
180180 defer tracy.end();
181181
182 try stubs_helper.writePreamble(macho_file, bw);
182 try stubs_helper.writePreamble(macho_file, writer);
183183
184184 const cpu_arch = macho_file.getTarget().cpu.arch;
185185 const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
......@@ -195,24 +195,24 @@ pub const StubsHelperSection = struct {
195195 const target: i64 = @intCast(sect.addr);
196196 switch (cpu_arch) {
197197 .x86_64 => {
198 try bw.writeByte(0x68);
199 try bw.writeInt(u32, offset, .little);
200 try bw.writeByte(0xe9);
201 try bw.writeInt(i32, @intCast(target - source - 6 - 4), .little);
198 try writer.writeByte(0x68);
199 try writer.writeInt(u32, offset, .little);
200 try writer.writeByte(0xe9);
201 try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);
202202 },
203203 .aarch64 => {
204204 const literal = blk: {
205205 const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);
206206 break :blk std.math.cast(u18, div_res) orelse return error.Overflow;
207207 };
208 try bw.writeInt(u32, aarch64.Instruction.ldrLiteral(
208 try writer.writeInt(u32, aarch64.Instruction.ldrLiteral(
209209 .w16,
210210 literal,
211211 ).toU32(), .little);
212212 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse
213213 return error.Overflow;
214 try bw.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
215 try bw.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
214 try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
215 try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
216216 },
217217 else => unreachable,
218218 }
......@@ -220,7 +220,7 @@ pub const StubsHelperSection = struct {
220220 }
221221 }
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 {
224224 _ = stubs_helper;
225225 const obj = macho_file.getInternalObject().?;
226226 const cpu_arch = macho_file.getTarget().cpu.arch;
......@@ -235,21 +235,21 @@ pub const StubsHelperSection = struct {
235235 };
236236 switch (cpu_arch) {
237237 .x86_64 => {
238 try bw.writeAll(&.{ 0x4c, 0x8d, 0x1d });
239 try bw.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);
240 try bw.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
241 try bw.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);
242 try bw.writeByte(0x90);
238 try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d });
239 try writer.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);
240 try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
241 try writer.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);
242 try writer.writeByte(0x90);
243243 },
244244 .aarch64 => {
245245 {
246246 // TODO relax if possible
247247 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);
249249 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);
251251 }
252 try bw.writeInt(u32, aarch64.Instruction.stp(
252 try writer.writeInt(u32, aarch64.Instruction.stp(
253253 .x16,
254254 .x17,
255255 aarch64.Register.sp,
......@@ -258,15 +258,15 @@ pub const StubsHelperSection = struct {
258258 {
259259 // TODO relax if possible
260260 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);
262262 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(
264264 .x16,
265265 .x16,
266266 aarch64.Instruction.LoadStoreOffset.imm(off),
267267 ).toU32(), .little);
268268 }
269 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
269 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
270270 },
271271 else => unreachable,
272272 }
......@@ -279,7 +279,7 @@ pub const LaSymbolPtrSection = struct {
279279 return macho_file.stubs.symbols.items.len * @sizeOf(u64);
280280 }
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 {
283283 const tracy = trace(@src());
284284 defer tracy.end();
285285 _ = laptr;
......@@ -290,12 +290,12 @@ pub const LaSymbolPtrSection = struct {
290290 const sym = ref.getSymbol(macho_file).?;
291291 if (sym.flags.weak) {
292292 const value = sym.getAddress(.{ .stubs = false }, macho_file);
293 try bw.writeInt(u64, @intCast(value), .little);
293 try writer.writeInt(u64, @intCast(value), .little);
294294 } else {
295295 const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) +
296296 StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx;
297297 stub_helper_idx += 1;
298 try bw.writeInt(u64, @intCast(value), .little);
298 try writer.writeInt(u64, @intCast(value), .little);
299299 }
300300 }
301301 }
......@@ -329,16 +329,16 @@ pub const TlvPtrSection = struct {
329329 return tlv.symbols.items.len * @sizeOf(u64);
330330 }
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 {
333333 const tracy = trace(@src());
334334 defer tracy.end();
335335
336336 for (tlv.symbols.items) |ref| {
337337 const sym = ref.getSymbol(macho_file).?;
338338 if (sym.flags.import) {
339 try bw.writeInt(u64, 0, .little);
339 try writer.writeInt(u64, 0, .little);
340340 } else {
341 try bw.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
341 try writer.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
342342 }
343343 }
344344 }
......@@ -400,7 +400,7 @@ pub const ObjcStubsSection = struct {
400400 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
401401 }
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 {
404404 const tracy = trace(@src());
405405 defer tracy.end();
406406
......@@ -411,18 +411,18 @@ pub const ObjcStubsSection = struct {
411411 const addr = objc.getAddress(@intCast(idx), macho_file);
412412 switch (macho_file.getTarget().cpu.arch) {
413413 .x86_64 => {
414 try bw.writeAll(&.{ 0x48, 0x8b, 0x35 });
414 try writer.writeAll(&.{ 0x48, 0x8b, 0x35 });
415415 {
416416 const target = sym.getObjcSelrefsAddress(macho_file);
417417 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);
419419 }
420 try bw.writeAll(&.{ 0xff, 0x25 });
420 try writer.writeAll(&.{ 0xff, 0x25 });
421421 {
422422 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
423423 const target = target_sym.getGotAddress(macho_file);
424424 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);
426426 }
427427 },
428428 .aarch64 => {
......@@ -430,9 +430,9 @@ pub const ObjcStubsSection = struct {
430430 const target = sym.getObjcSelrefsAddress(macho_file);
431431 const source = addr;
432432 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);
434434 const off = try math.divExact(u12, @truncate(target), 8);
435 try bw.writeInt(
435 try writer.writeInt(
436436 u32,
437437 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
438438 .little,
......@@ -443,18 +443,18 @@ pub const ObjcStubsSection = struct {
443443 const target = target_sym.getGotAddress(macho_file);
444444 const source = addr + 2 * @sizeOf(u32);
445445 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);
447447 const off = try math.divExact(u12, @truncate(target), 8);
448 try bw.writeInt(
448 try writer.writeInt(
449449 u32,
450450 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
451451 .little,
452452 );
453453 }
454 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
455 try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
456 try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
457 try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
454 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
455 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
456 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
457 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
458458 },
459459 else => unreachable,
460460 }
......@@ -496,7 +496,7 @@ pub const Indsymtab = struct {
496496 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
497497 }
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 {
500500 const tracy = trace(@src());
501501 defer tracy.end();
502502
......@@ -505,21 +505,21 @@ pub const Indsymtab = struct {
505505 for (macho_file.stubs.symbols.items) |ref| {
506506 const sym = ref.getSymbol(macho_file).?;
507507 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
508 try bw.writeInt(u32, idx, .little);
508 try writer.writeInt(u32, idx, .little);
509509 }
510510 }
511511
512512 for (macho_file.got.symbols.items) |ref| {
513513 const sym = ref.getSymbol(macho_file).?;
514514 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
515 try bw.writeInt(u32, idx, .little);
515 try writer.writeInt(u32, idx, .little);
516516 }
517517 }
518518
519519 for (macho_file.stubs.symbols.items) |ref| {
520520 const sym = ref.getSymbol(macho_file).?;
521521 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
522 try bw.writeInt(u32, idx, .little);
522 try writer.writeInt(u32, idx, .little);
523523 }
524524 }
525525 }
......@@ -573,7 +573,7 @@ pub const DataInCode = struct {
573573 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;
574574 }
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 {
577577 const base_address = if (!macho_file.base.isRelocatable())
578578 macho_file.getTextSegment().vmaddr
579579 else
......@@ -581,7 +581,7 @@ pub const DataInCode = struct {
581581 for (dice.entries.items) |entry| {
582582 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);
583583 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{
585585 .offset = @intCast(offset),
586586 .length = entry.length,
587587 .kind = entry.kind,