authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-01 18:14:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-07 22:43:52-07:00
logc8fcd2ff2c032b2de8cc1a57e075552d1cab35df
tree7155f58049ecd0e948533f6b64cba1553dd33ae2
parentf71d97e4cbb0e56213cb76657ad6c9edf6134868

MachO: update to new std.io APIs


25 files changed, 1580 insertions(+), 1649 deletions(-)

lib/compiler/aro/aro/Diagnostics.zig+4-4
......@@ -444,7 +444,7 @@ pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void {
444444 printRt(m, prop.msg, .{"{s}"}, .{&str});
445445 } else {
446446 var buf: [3]u8 = undefined;
447 const str = std.fmt.bufPrint(&buf, "x{x}", .{&.{msg.extra.invalid_escape.char}}) catch unreachable;
447 const str = std.fmt.bufPrint(&buf, "x{x}", .{msg.extra.invalid_escape.char}) catch unreachable;
448448 printRt(m, prop.msg, .{"{s}"}, .{str});
449449 }
450450 },
......@@ -525,13 +525,13 @@ fn tagKind(d: *Diagnostics, tag: Tag, langopts: LangOpts) Kind {
525525}
526526
527527const MsgWriter = struct {
528 w: std.io.BufferedWriter(4096, std.fs.File.Writer),
528 w: *std.fs.File.Writer,
529529 config: std.io.tty.Config,
530530
531 fn init(config: std.io.tty.Config) MsgWriter {
531 fn init(config: std.io.tty.Config, buffer: []u8) MsgWriter {
532532 std.debug.lockStdErr();
533533 return .{
534 .w = std.io.bufferedWriter(std.fs.File.stderr().deprecatedWriter()),
534 .w = std.fs.stderr().writer(buffer),
535535 .config = config,
536536 };
537537 }
src/deprecated.zig created+431
......@@ -0,0 +1,431 @@
1//! Deprecated. Stop using this API
2
3const std = @import("std");
4const math = std.math;
5const mem = std.mem;
6const Allocator = mem.Allocator;
7const assert = std.debug.assert;
8const testing = std.testing;
9
10pub fn LinearFifo(comptime T: type) type {
11 return struct {
12 allocator: Allocator,
13 buf: []T,
14 head: usize,
15 count: usize,
16
17 const Self = @This();
18
19 pub fn init(allocator: Allocator) Self {
20 return .{
21 .allocator = allocator,
22 .buf = &.{},
23 .head = 0,
24 .count = 0,
25 };
26 }
27
28 pub fn deinit(self: *Self) void {
29 self.allocator.free(self.buf);
30 self.* = undefined;
31 }
32
33 pub fn realign(self: *Self) void {
34 if (self.buf.len - self.head >= self.count) {
35 mem.copyForwards(T, self.buf[0..self.count], self.buf[self.head..][0..self.count]);
36 self.head = 0;
37 } else {
38 var tmp: [4096 / 2 / @sizeOf(T)]T = undefined;
39
40 while (self.head != 0) {
41 const n = @min(self.head, tmp.len);
42 const m = self.buf.len - n;
43 @memcpy(tmp[0..n], self.buf[0..n]);
44 mem.copyForwards(T, self.buf[0..m], self.buf[n..][0..m]);
45 @memcpy(self.buf[m..][0..n], tmp[0..n]);
46 self.head -= n;
47 }
48 }
49 { // set unused area to undefined
50 const unused = mem.sliceAsBytes(self.buf[self.count..]);
51 @memset(unused, undefined);
52 }
53 }
54
55 /// Reduce allocated capacity to `size`.
56 pub fn shrink(self: *Self, size: usize) void {
57 assert(size >= self.count);
58 self.realign();
59 self.buf = self.allocator.realloc(self.buf, size) catch |e| switch (e) {
60 error.OutOfMemory => return, // no problem, capacity is still correct then.
61 };
62 }
63
64 /// Ensure that the buffer can fit at least `size` items
65 pub fn ensureTotalCapacity(self: *Self, size: usize) !void {
66 if (self.buf.len >= size) return;
67 self.realign();
68 const new_size = math.ceilPowerOfTwo(usize, size) catch return error.OutOfMemory;
69 self.buf = try self.allocator.realloc(self.buf, new_size);
70 }
71
72 /// Makes sure at least `size` items are unused
73 pub fn ensureUnusedCapacity(self: *Self, size: usize) error{OutOfMemory}!void {
74 if (self.writableLength() >= size) return;
75
76 return try self.ensureTotalCapacity(math.add(usize, self.count, size) catch return error.OutOfMemory);
77 }
78
79 /// Returns number of items currently in fifo
80 pub fn readableLength(self: Self) usize {
81 return self.count;
82 }
83
84 /// Returns a writable slice from the 'read' end of the fifo
85 fn readableSliceMut(self: Self, offset: usize) []T {
86 if (offset > self.count) return &[_]T{};
87
88 var start = self.head + offset;
89 if (start >= self.buf.len) {
90 start -= self.buf.len;
91 return self.buf[start .. start + (self.count - offset)];
92 } else {
93 const end = @min(self.head + self.count, self.buf.len);
94 return self.buf[start..end];
95 }
96 }
97
98 /// Returns a readable slice from `offset`
99 pub fn readableSlice(self: Self, offset: usize) []const T {
100 return self.readableSliceMut(offset);
101 }
102
103 pub fn readableSliceOfLen(self: *Self, len: usize) []const T {
104 assert(len <= self.count);
105 const buf = self.readableSlice(0);
106 if (buf.len >= len) {
107 return buf[0..len];
108 } else {
109 self.realign();
110 return self.readableSlice(0)[0..len];
111 }
112 }
113
114 /// Discard first `count` items in the fifo
115 pub fn discard(self: *Self, count: usize) void {
116 assert(count <= self.count);
117 { // set old range to undefined. Note: may be wrapped around
118 const slice = self.readableSliceMut(0);
119 if (slice.len >= count) {
120 const unused = mem.sliceAsBytes(slice[0..count]);
121 @memset(unused, undefined);
122 } else {
123 const unused = mem.sliceAsBytes(slice[0..]);
124 @memset(unused, undefined);
125 const unused2 = mem.sliceAsBytes(self.readableSliceMut(slice.len)[0 .. count - slice.len]);
126 @memset(unused2, undefined);
127 }
128 }
129 var head = self.head + count;
130 // Note it is safe to do a wrapping subtract as
131 // bitwise & with all 1s is a noop
132 head &= self.buf.len -% 1;
133 self.head = head;
134 self.count -= count;
135 }
136
137 /// Read the next item from the fifo
138 pub fn readItem(self: *Self) ?T {
139 if (self.count == 0) return null;
140
141 const c = self.buf[self.head];
142 self.discard(1);
143 return c;
144 }
145
146 /// Read data from the fifo into `dst`, returns number of items copied.
147 pub fn read(self: *Self, dst: []T) usize {
148 var dst_left = dst;
149
150 while (dst_left.len > 0) {
151 const slice = self.readableSlice(0);
152 if (slice.len == 0) break;
153 const n = @min(slice.len, dst_left.len);
154 @memcpy(dst_left[0..n], slice[0..n]);
155 self.discard(n);
156 dst_left = dst_left[n..];
157 }
158
159 return dst.len - dst_left.len;
160 }
161
162 /// Same as `read` except it returns an error union
163 /// The purpose of this function existing is to match `std.io.Reader` API.
164 fn readFn(self: *Self, dest: []u8) error{}!usize {
165 return self.read(dest);
166 }
167
168 /// Returns number of items available in fifo
169 pub fn writableLength(self: Self) usize {
170 return self.buf.len - self.count;
171 }
172
173 /// Returns the first section of writable buffer.
174 /// Note that this may be of length 0
175 pub fn writableSlice(self: Self, offset: usize) []T {
176 if (offset > self.buf.len) return &[_]T{};
177
178 const tail = self.head + offset + self.count;
179 if (tail < self.buf.len) {
180 return self.buf[tail..];
181 } else {
182 return self.buf[tail - self.buf.len ..][0 .. self.writableLength() - offset];
183 }
184 }
185
186 /// Returns a writable buffer of at least `size` items, allocating memory as needed.
187 /// Use `fifo.update` once you've written data to it.
188 pub fn writableWithSize(self: *Self, size: usize) ![]T {
189 try self.ensureUnusedCapacity(size);
190
191 // try to avoid realigning buffer
192 var slice = self.writableSlice(0);
193 if (slice.len < size) {
194 self.realign();
195 slice = self.writableSlice(0);
196 }
197 return slice;
198 }
199
200 /// Update the tail location of the buffer (usually follows use of writable/writableWithSize)
201 pub fn update(self: *Self, count: usize) void {
202 assert(self.count + count <= self.buf.len);
203 self.count += count;
204 }
205
206 /// Appends the data in `src` to the fifo.
207 /// You must have ensured there is enough space.
208 pub fn writeAssumeCapacity(self: *Self, src: []const T) void {
209 assert(self.writableLength() >= src.len);
210
211 var src_left = src;
212 while (src_left.len > 0) {
213 const writable_slice = self.writableSlice(0);
214 assert(writable_slice.len != 0);
215 const n = @min(writable_slice.len, src_left.len);
216 @memcpy(writable_slice[0..n], src_left[0..n]);
217 self.update(n);
218 src_left = src_left[n..];
219 }
220 }
221
222 /// Write a single item to the fifo
223 pub fn writeItem(self: *Self, item: T) !void {
224 try self.ensureUnusedCapacity(1);
225 return self.writeItemAssumeCapacity(item);
226 }
227
228 pub fn writeItemAssumeCapacity(self: *Self, item: T) void {
229 var tail = self.head + self.count;
230 tail &= self.buf.len - 1;
231 self.buf[tail] = item;
232 self.update(1);
233 }
234
235 /// Appends the data in `src` to the fifo.
236 /// Allocates more memory as necessary
237 pub fn write(self: *Self, src: []const T) !void {
238 try self.ensureUnusedCapacity(src.len);
239
240 return self.writeAssumeCapacity(src);
241 }
242
243 /// Same as `write` except it returns the number of bytes written, which is always the same
244 /// as `bytes.len`. The purpose of this function existing is to match `std.io.Writer` API.
245 fn appendWrite(self: *Self, bytes: []const u8) error{OutOfMemory}!usize {
246 try self.write(bytes);
247 return bytes.len;
248 }
249
250 /// Make `count` items available before the current read location
251 fn rewind(self: *Self, count: usize) void {
252 assert(self.writableLength() >= count);
253
254 var head = self.head + (self.buf.len - count);
255 head &= self.buf.len - 1;
256 self.head = head;
257 self.count += count;
258 }
259
260 /// Place data back into the read stream
261 pub fn unget(self: *Self, src: []const T) !void {
262 try self.ensureUnusedCapacity(src.len);
263
264 self.rewind(src.len);
265
266 const slice = self.readableSliceMut(0);
267 if (src.len < slice.len) {
268 @memcpy(slice[0..src.len], src);
269 } else {
270 @memcpy(slice, src[0..slice.len]);
271 const slice2 = self.readableSliceMut(slice.len);
272 @memcpy(slice2[0 .. src.len - slice.len], src[slice.len..]);
273 }
274 }
275
276 /// Returns the item at `offset`.
277 /// Asserts offset is within bounds.
278 pub fn peekItem(self: Self, offset: usize) T {
279 assert(offset < self.count);
280
281 var index = self.head + offset;
282 index &= self.buf.len - 1;
283 return self.buf[index];
284 }
285
286 pub fn toOwnedSlice(self: *Self) Allocator.Error![]T {
287 if (self.head != 0) self.realign();
288 assert(self.head == 0);
289 assert(self.count <= self.buf.len);
290 const allocator = self.allocator;
291 if (allocator.resize(self.buf, self.count)) {
292 const result = self.buf[0..self.count];
293 self.* = Self.init(allocator);
294 return result;
295 }
296 const new_memory = try allocator.dupe(T, self.buf[0..self.count]);
297 allocator.free(self.buf);
298 self.* = Self.init(allocator);
299 return new_memory;
300 }
301 };
302}
303
304test "LinearFifo(u8, .Dynamic) discard(0) from empty buffer should not error on overflow" {
305 var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator);
306 defer fifo.deinit();
307
308 // If overflow is not explicitly allowed this will crash in debug / safe mode
309 fifo.discard(0);
310}
311
312test "LinearFifo(u8, .Dynamic)" {
313 var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator);
314 defer fifo.deinit();
315
316 try fifo.write("HELLO");
317 try testing.expectEqual(@as(usize, 5), fifo.readableLength());
318 try testing.expectEqualSlices(u8, "HELLO", fifo.readableSlice(0));
319
320 {
321 var i: usize = 0;
322 while (i < 5) : (i += 1) {
323 try fifo.write(&[_]u8{fifo.peekItem(i)});
324 }
325 try testing.expectEqual(@as(usize, 10), fifo.readableLength());
326 try testing.expectEqualSlices(u8, "HELLOHELLO", fifo.readableSlice(0));
327 }
328
329 {
330 try testing.expectEqual(@as(u8, 'H'), fifo.readItem().?);
331 try testing.expectEqual(@as(u8, 'E'), fifo.readItem().?);
332 try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?);
333 try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?);
334 try testing.expectEqual(@as(u8, 'O'), fifo.readItem().?);
335 }
336 try testing.expectEqual(@as(usize, 5), fifo.readableLength());
337
338 { // Writes that wrap around
339 try testing.expectEqual(@as(usize, 11), fifo.writableLength());
340 try testing.expectEqual(@as(usize, 6), fifo.writableSlice(0).len);
341 fifo.writeAssumeCapacity("6<chars<11");
342 try testing.expectEqualSlices(u8, "HELLO6<char", fifo.readableSlice(0));
343 try testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(11));
344 try testing.expectEqualSlices(u8, "11", fifo.readableSlice(13));
345 try testing.expectEqualSlices(u8, "", fifo.readableSlice(15));
346 fifo.discard(11);
347 try testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(0));
348 fifo.discard(4);
349 try testing.expectEqual(@as(usize, 0), fifo.readableLength());
350 }
351
352 {
353 const buf = try fifo.writableWithSize(12);
354 try testing.expectEqual(@as(usize, 12), buf.len);
355 var i: u8 = 0;
356 while (i < 10) : (i += 1) {
357 buf[i] = i + 'a';
358 }
359 fifo.update(10);
360 try testing.expectEqualSlices(u8, "abcdefghij", fifo.readableSlice(0));
361 }
362
363 {
364 try fifo.unget("prependedstring");
365 var result: [30]u8 = undefined;
366 try testing.expectEqualSlices(u8, "prependedstringabcdefghij", result[0..fifo.read(&result)]);
367 try fifo.unget("b");
368 try fifo.unget("a");
369 try testing.expectEqualSlices(u8, "ab", result[0..fifo.read(&result)]);
370 }
371
372 fifo.shrink(0);
373
374 {
375 try fifo.writer().print("{s}, {s}!", .{ "Hello", "World" });
376 var result: [30]u8 = undefined;
377 try testing.expectEqualSlices(u8, "Hello, World!", result[0..fifo.read(&result)]);
378 try testing.expectEqual(@as(usize, 0), fifo.readableLength());
379 }
380
381 {
382 try fifo.writer().writeAll("This is a test");
383 var result: [30]u8 = undefined;
384 try testing.expectEqualSlices(u8, "This", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
385 try testing.expectEqualSlices(u8, "is", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
386 try testing.expectEqualSlices(u8, "a", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
387 try testing.expectEqualSlices(u8, "test", (try fifo.reader().readUntilDelimiterOrEof(&result, ' ')).?);
388 }
389
390 {
391 try fifo.ensureTotalCapacity(1);
392 var in_fbs = std.io.fixedBufferStream("pump test");
393 var out_buf: [50]u8 = undefined;
394 var out_fbs = std.io.fixedBufferStream(&out_buf);
395 try fifo.pump(in_fbs.reader(), out_fbs.writer());
396 try testing.expectEqualSlices(u8, in_fbs.buffer, out_fbs.getWritten());
397 }
398}
399
400test LinearFifo {
401 inline for ([_]type{ u1, u8, u16, u64 }) |T| {
402 const FifoType = LinearFifo(T);
403 var fifo: FifoType = .init(testing.allocator);
404 defer fifo.deinit();
405
406 try fifo.write(&[_]T{ 0, 1, 1, 0, 1 });
407 try testing.expectEqual(@as(usize, 5), fifo.readableLength());
408
409 {
410 try testing.expectEqual(@as(T, 0), fifo.readItem().?);
411 try testing.expectEqual(@as(T, 1), fifo.readItem().?);
412 try testing.expectEqual(@as(T, 1), fifo.readItem().?);
413 try testing.expectEqual(@as(T, 0), fifo.readItem().?);
414 try testing.expectEqual(@as(T, 1), fifo.readItem().?);
415 try testing.expectEqual(@as(usize, 0), fifo.readableLength());
416 }
417
418 {
419 try fifo.writeItem(1);
420 try fifo.writeItem(1);
421 try fifo.writeItem(1);
422 try testing.expectEqual(@as(usize, 3), fifo.readableLength());
423 }
424
425 {
426 var readBuf: [3]T = undefined;
427 const n = fifo.read(&readBuf);
428 try testing.expectEqual(@as(usize, 3), n); // NOTE: It should be the number of items.
429 }
430 }
431}
src/link/MachO.zig+157-196
......@@ -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: ?u8 = null,
45text_seg_index: ?u8 = null,
46linkedit_seg_index: ?u8 = null,
44pagezero_seg_index: ?u4 = null,
45text_seg_index: ?u4 = null,
46linkedit_seg_index: ?u4 = 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: ?u8 = null,
80zig_const_seg_index: ?u8 = null,
81zig_data_seg_index: ?u8 = null,
82zig_bss_seg_index: ?u8 = null,
79zig_text_seg_index: ?u4 = null,
80zig_const_seg_index: ?u4 = null,
81zig_data_seg_index: ?u4 = null,
82zig_bss_seg_index: ?u4 = null,
8383
8484/// Tracked section headers with incremental updates to Zig object.
8585zig_text_sect_index: ?u8 = null,
......@@ -543,7 +543,7 @@ pub fn flush(
543543 self.allocateSyntheticSymbols();
544544
545545 if (build_options.enable_logging) {
546 state_log.debug("{}", .{self.dumpState()});
546 state_log.debug("{f}", .{self.dumpState()});
547547 }
548548
549549 // Beyond this point, everything has been allocated a virtual address and we can resolve
......@@ -591,6 +591,7 @@ pub fn flush(
591591 error.NoSpaceLeft => unreachable,
592592 error.OutOfMemory => return error.OutOfMemory,
593593 error.LinkFailure => return error.LinkFailure,
594 else => unreachable,
594595 };
595596 try self.writeHeader(ncmds, sizeofcmds);
596597 self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) {
......@@ -677,12 +678,12 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
677678
678679 try argv.append("-platform_version");
679680 try argv.append(@tagName(self.platform.os_tag));
680 try argv.append(try std.fmt.allocPrint(arena, "{}", .{self.platform.version}));
681 try argv.append(try std.fmt.allocPrint(arena, "{f}", .{self.platform.version}));
681682
682683 if (self.sdk_version) |ver| {
683684 try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}", .{ ver.major, ver.minor }));
684685 } else {
685 try argv.append(try std.fmt.allocPrint(arena, "{}", .{self.platform.version}));
686 try argv.append(try std.fmt.allocPrint(arena, "{f}", .{self.platform.version}));
686687 }
687688
688689 if (comp.sysroot) |syslibroot| {
......@@ -863,7 +864,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {
863864
864865 const path, const file = input.pathAndFile().?;
865866 // TODO don't classify now, it's too late. The input file has already been classified
866 log.debug("classifying input file {}", .{path});
867 log.debug("classifying input file {f}", .{path});
867868
868869 const fh = try self.addFileHandle(file);
869870 var buffer: [Archive.SARMAG]u8 = undefined;
......@@ -1074,7 +1075,7 @@ fn accessLibPath(
10741075
10751076 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
10761077 test_path.clearRetainingCapacity();
1077 try test_path.writer().print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
1078 try test_path.print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
10781079 try checked_paths.append(try arena.dupe(u8, test_path.items));
10791080 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
10801081 error.FileNotFound => continue,
......@@ -1097,7 +1098,7 @@ fn accessFrameworkPath(
10971098
10981099 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
10991100 test_path.clearRetainingCapacity();
1100 try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
1101 try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
11011102 search_dir,
11021103 name,
11031104 name,
......@@ -1178,9 +1179,9 @@ fn parseDependentDylibs(self: *MachO) !void {
11781179 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
11791180 test_path.clearRetainingCapacity();
11801181 if (self.base.comp.sysroot) |root| {
1181 try test_path.writer().print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
1182 try test_path.print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
11821183 } else {
1183 try test_path.writer().print("{s}{s}", .{ path, ext });
1184 try test_path.print("{s}{s}", .{ path, ext });
11841185 }
11851186 try checked_paths.append(try arena.dupe(u8, test_path.items));
11861187 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
......@@ -1591,7 +1592,7 @@ fn reportUndefs(self: *MachO) !void {
15911592 const ref = refs.items[inote];
15921593 const file = self.getFile(ref.file).?;
15931594 const atom = ref.getAtom(self).?;
1594 err.addNote("referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) });
1595 err.addNote("referenced by {f}:{s}", .{ file.fmtPath(), atom.getName(self) });
15951596 }
15961597
15971598 if (refs.items.len > max_notes) {
......@@ -2131,7 +2132,7 @@ fn initSegments(self: *MachO) !void {
21312132
21322133 mem.sort(Entry, entries.items, self, Entry.lessThan);
21332134
2134 const backlinks = try gpa.alloc(u8, entries.items.len);
2135 const backlinks = try gpa.alloc(u4, entries.items.len);
21352136 defer gpa.free(backlinks);
21362137 for (entries.items, 0..) |entry, i| {
21372138 backlinks[entry.index] = @intCast(i);
......@@ -2145,7 +2146,7 @@ fn initSegments(self: *MachO) !void {
21452146 self.segments.appendAssumeCapacity(segments[sorted.index]);
21462147 }
21472148
2148 for (&[_]*?u8{
2149 for (&[_]*?u4{
21492150 &self.pagezero_seg_index,
21502151 &self.text_seg_index,
21512152 &self.linkedit_seg_index,
......@@ -2163,7 +2164,7 @@ fn initSegments(self: *MachO) !void {
21632164 for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| {
21642165 const segname = header.segName();
21652166 const segment_id = self.getSegmentByName(segname) orelse blk: {
2166 const segment_id = @as(u8, @intCast(self.segments.items.len));
2167 const segment_id: u4 = @intCast(self.segments.items.len);
21672168 const protection = getSegmentProt(segname);
21682169 try self.segments.append(gpa, .{
21692170 .cmdsize = @sizeOf(macho.segment_command_64),
......@@ -2526,10 +2527,8 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
25262527
25272528 const doWork = struct {
25282529 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
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());
2530 var bw: Writer = .fixed(buffer[try macho_file.cast(usize, th.value)..][0..th.size()]);
2531 try th.write(macho_file, &bw);
25332532 }
25342533 }.doWork;
25352534 const out = self.sections.items(.out)[thunk.out_n_sect].items;
......@@ -2556,15 +2555,15 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {
25562555
25572556 const doWork = struct {
25582557 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {
2559 var stream = std.io.fixedBufferStream(buffer);
2558 var bw: Writer = .fixed(buffer);
25602559 switch (tag) {
25612560 .eh_frame => eh_frame.write(macho_file, buffer),
2562 .unwind_info => try macho_file.unwind_info.write(macho_file, buffer),
2563 .got => try macho_file.got.write(macho_file, stream.writer()),
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()),
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),
25682567 }
25692568 }
25702569 }.doWork;
......@@ -2605,8 +2604,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {
26052604 try macho_file.lazy_bind_section.updateSize(macho_file);
26062605 const sect_id = macho_file.stubs_helper_sect_index.?;
26072606 const out = &macho_file.sections.items(.out)[sect_id];
2608 var stream = std.io.fixedBufferStream(out.items);
2609 try macho_file.stubs_helper.write(macho_file, stream.writer());
2607 var bw: Writer = .fixed(out.items);
2608 try macho_file.stubs_helper.write(macho_file, &bw);
26102609 }
26112610 }.doWork;
26122611 doWork(self) catch |err|
......@@ -2665,46 +2664,49 @@ fn writeDyldInfo(self: *MachO) !void {
26652664 needed_size += cmd.lazy_bind_size;
26662665 needed_size += cmd.export_size;
26672666
2668 const buffer = try gpa.alloc(u8, needed_size);
2669 defer gpa.free(buffer);
2670 @memset(buffer, 0);
2671
2672 var stream = std.io.fixedBufferStream(buffer);
2673 const writer = stream.writer();
2667 var bw: Writer = .fixed(try gpa.alloc(u8, needed_size));
2668 defer gpa.free(bw.buffer);
2669 @memset(bw.buffer, 0);
26742670
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);
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);
26852681}
26862682
2687pub fn writeDataInCode(self: *MachO) !void {
2683pub fn writeDataInCode(self: *MachO) link.File.FlushError!void {
26882684 const tracy = trace(@src());
26892685 defer tracy.end();
26902686 const gpa = self.base.comp.gpa;
26912687 const cmd = self.data_in_code_cmd;
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);
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);
26962695}
26972696
26982697fn writeIndsymtab(self: *MachO) !void {
26992698 const tracy = trace(@src());
27002699 defer tracy.end();
2700
27012701 const gpa = self.base.comp.gpa;
27022702 const cmd = self.dysymtab_cmd;
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);
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);
27082710}
27092711
27102712pub fn writeSymtabToFile(self: *MachO) !void {
......@@ -2814,15 +2816,12 @@ fn calcSymtabSize(self: *MachO) !void {
28142816 }
28152817}
28162818
2817fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2819fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
28182820 const comp = self.base.comp;
28192821 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);
28232822
2824 var stream = std.io.fixedBufferStream(buffer);
2825 const writer = stream.writer();
2823 var bw: Writer = .fixed(try gpa.alloc(u8, try load_commands.calcLoadCommandsSize(self, false)));
2824 defer gpa.free(bw.buffer);
28262825
28272826 var ncmds: usize = 0;
28282827
......@@ -2831,26 +2830,26 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
28312830 const slice = self.sections.slice();
28322831 var sect_id: usize = 0;
28332832 for (self.segments.items) |seg| {
2834 try writer.writeStruct(seg);
2833 try bw.writeStruct(seg);
28352834 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
2836 try writer.writeStruct(header);
2835 try bw.writeStruct(header);
28372836 }
28382837 sect_id += seg.nsects;
28392838 }
28402839 ncmds += self.segments.items.len;
28412840 }
28422841
2843 try writer.writeStruct(self.dyld_info_cmd);
2842 try bw.writeStruct(self.dyld_info_cmd);
28442843 ncmds += 1;
2845 try writer.writeStruct(self.function_starts_cmd);
2844 try bw.writeStruct(self.function_starts_cmd);
28462845 ncmds += 1;
2847 try writer.writeStruct(self.data_in_code_cmd);
2846 try bw.writeStruct(self.data_in_code_cmd);
28482847 ncmds += 1;
2849 try writer.writeStruct(self.symtab_cmd);
2848 try bw.writeStruct(self.symtab_cmd);
28502849 ncmds += 1;
2851 try writer.writeStruct(self.dysymtab_cmd);
2850 try bw.writeStruct(self.dysymtab_cmd);
28522851 ncmds += 1;
2853 try load_commands.writeDylinkerLC(writer);
2852 try load_commands.writeDylinkerLC(&bw);
28542853 ncmds += 1;
28552854
28562855 if (self.getInternalObject()) |obj| {
......@@ -2861,7 +2860,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
28612860 0
28622861 else
28632862 @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));
2864 try writer.writeStruct(macho.entry_point_command{
2863 try bw.writeStruct(macho.entry_point_command{
28652864 .entryoff = entryoff,
28662865 .stacksize = self.base.stack_size,
28672866 });
......@@ -2870,35 +2869,35 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
28702869 }
28712870
28722871 if (self.base.isDynLib()) {
2873 try load_commands.writeDylibIdLC(self, writer);
2872 try load_commands.writeDylibIdLC(self, &bw);
28742873 ncmds += 1;
28752874 }
28762875
28772876 for (self.rpath_list) |rpath| {
2878 try load_commands.writeRpathLC(rpath, writer);
2877 try load_commands.writeRpathLC(&bw, rpath);
28792878 ncmds += 1;
28802879 }
28812880 if (comp.config.any_sanitize_thread) {
28822881 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
28832882 defer gpa.free(path);
28842883 const rpath = std.fs.path.dirname(path) orelse ".";
2885 try load_commands.writeRpathLC(rpath, writer);
2884 try load_commands.writeRpathLC(&bw, rpath);
28862885 ncmds += 1;
28872886 }
28882887
2889 try writer.writeStruct(macho.source_version_command{ .version = 0 });
2888 try bw.writeStruct(macho.source_version_command{ .version = 0 });
28902889 ncmds += 1;
28912890
28922891 if (self.platform.isBuildVersionCompatible()) {
2893 try load_commands.writeBuildVersionLC(self.platform, self.sdk_version, writer);
2892 try load_commands.writeBuildVersionLC(&bw, self.platform, self.sdk_version);
28942893 ncmds += 1;
28952894 } else {
2896 try load_commands.writeVersionMinLC(self.platform, self.sdk_version, writer);
2895 try load_commands.writeVersionMinLC(&bw, self.platform, self.sdk_version);
28972896 ncmds += 1;
28982897 }
28992898
2900 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos;
2901 try writer.writeStruct(self.uuid_cmd);
2899 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + bw.count;
2900 try bw.writeStruct(self.uuid_cmd);
29022901 ncmds += 1;
29032902
29042903 for (self.dylibs.items) |index| {
......@@ -2916,20 +2915,19 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
29162915 .timestamp = dylib_id.timestamp,
29172916 .current_version = dylib_id.current_version,
29182917 .compatibility_version = dylib_id.compatibility_version,
2919 }, writer);
2918 }, &bw);
29202919 ncmds += 1;
29212920 }
29222921
29232922 if (self.requiresCodeSig()) {
2924 try writer.writeStruct(self.codesig_cmd);
2923 try bw.writeStruct(self.codesig_cmd);
29252924 ncmds += 1;
29262925 }
29272926
2928 assert(stream.pos == needed_size);
2929
2930 try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
2927 assert(bw.end == bw.buffer.len);
2928 try self.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
29312929
2932 return .{ ncmds, buffer.len, uuid_cmd_offset };
2930 return .{ ncmds, bw.end, uuid_cmd_offset };
29332931}
29342932
29352933fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {
......@@ -3012,27 +3010,27 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
30123010}
30133011
30143012pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
3013 const gpa = self.base.comp.gpa;
30153014 const seg = self.getTextSegment();
30163015 const offset = self.codesig_cmd.dataoff;
30173016
3018 var buffer = std.ArrayList(u8).init(self.base.comp.gpa);
3019 defer buffer.deinit();
3020 try buffer.ensureTotalCapacityPrecise(code_sig.size());
3017 var bw: Writer = .fixed(try gpa.alloc(u8, code_sig.size()));
3018 defer gpa.free(bw.buffer);
30213019 try code_sig.writeAdhocSignature(self, .{
30223020 .file = self.base.file.?,
30233021 .exec_seg_base = seg.fileoff,
30243022 .exec_seg_limit = seg.filesize,
30253023 .file_size = offset,
30263024 .dylib = self.base.isDynLib(),
3027 }, buffer.writer());
3028 assert(buffer.items.len == code_sig.size());
3025 }, &bw);
30293026
30303027 log.debug("writing code signature from 0x{x} to 0x{x}", .{
30313028 offset,
3032 offset + buffer.items.len,
3029 offset + bw.end,
30333030 });
30343031
3035 try self.pwriteAll(buffer.items, offset);
3032 assert(bw.end == bw.buffer.len);
3033 try self.pwriteAll(bw.buffer, offset);
30363034}
30373035
30383036pub fn updateFunc(
......@@ -3341,7 +3339,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
33413339 }
33423340
33433341 const appendSect = struct {
3344 fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u8) void {
3342 fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u4) void {
33453343 const sect = &macho_file.sections.items(.header)[sect_id];
33463344 const seg = macho_file.segments.items[seg_id];
33473345 sect.addr = seg.vmaddr;
......@@ -3600,7 +3598,7 @@ inline fn requiresThunks(self: MachO) bool {
36003598}
36013599
36023600pub fn isZigSegment(self: MachO, seg_id: u8) bool {
3603 inline for (&[_]?u8{
3601 inline for (&[_]?u4{
36043602 self.zig_text_seg_index,
36053603 self.zig_const_seg_index,
36063604 self.zig_data_seg_index,
......@@ -3648,9 +3646,9 @@ pub fn addSegment(self: *MachO, name: []const u8, opts: struct {
36483646 fileoff: u64 = 0,
36493647 filesize: u64 = 0,
36503648 prot: macho.vm_prot_t = macho.PROT.NONE,
3651}) error{OutOfMemory}!u8 {
3649}) error{OutOfMemory}!u4 {
36523650 const gpa = self.base.comp.gpa;
3653 const index = @as(u8, @intCast(self.segments.items.len));
3651 const index: u4 = @intCast(self.segments.items.len);
36543652 try self.segments.append(gpa, .{
36553653 .segname = makeStaticString(name),
36563654 .vmaddr = opts.vmaddr,
......@@ -3700,9 +3698,9 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 {
37003698 return buf;
37013699}
37023700
3703pub fn getSegmentByName(self: MachO, segname: []const u8) ?u8 {
3701pub fn getSegmentByName(self: MachO, segname: []const u8) ?u4 {
37043702 for (self.segments.items, 0..) |seg, i| {
3705 if (mem.eql(u8, segname, seg.segName())) return @as(u8, @intCast(i));
3703 if (mem.eql(u8, segname, seg.segName())) return @intCast(i);
37063704 } else return null;
37073705}
37083706
......@@ -3791,7 +3789,7 @@ pub fn reportParseError2(
37913789 const diags = &self.base.comp.link_diags;
37923790 var err = try diags.addErrorWithNotes(1);
37933791 try err.addMsg(format, args);
3794 err.addNote("while parsing {}", .{self.getFile(file_index).?.fmtPath()});
3792 err.addNote("while parsing {f}", .{self.getFile(file_index).?.fmtPath()});
37953793}
37963794
37973795fn reportMissingDependencyError(
......@@ -3806,7 +3804,7 @@ fn reportMissingDependencyError(
38063804 var err = try diags.addErrorWithNotes(2 + checked_paths.len);
38073805 try err.addMsg(format, args);
38083806 err.addNote("while resolving {s}", .{path});
3809 err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
3807 err.addNote("a dependency of {f}", .{self.getFile(parent).?.fmtPath()});
38103808 for (checked_paths) |p| {
38113809 err.addNote("tried {s}", .{p});
38123810 }
......@@ -3823,7 +3821,7 @@ fn reportDependencyError(
38233821 var err = try diags.addErrorWithNotes(2);
38243822 try err.addMsg(format, args);
38253823 err.addNote("while parsing {s}", .{path});
3826 err.addNote("a dependency of {}", .{self.getFile(parent).?.fmtPath()});
3824 err.addNote("a dependency of {f}", .{self.getFile(parent).?.fmtPath()});
38273825}
38283826
38293827fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
......@@ -3853,12 +3851,12 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
38533851
38543852 var err = try diags.addErrorWithNotes(nnotes + 1);
38553853 try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)});
3856 err.addNote("defined by {}", .{sym.getFile(self).?.fmtPath()});
3854 err.addNote("defined by {f}", .{sym.getFile(self).?.fmtPath()});
38573855
38583856 var inote: usize = 0;
38593857 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
38603858 const file = self.getFile(notes.items[inote]).?;
3861 err.addNote("defined by {}", .{file.fmtPath()});
3859 err.addNote("defined by {f}", .{file.fmtPath()});
38623860 }
38633861
38643862 if (notes.items.len > max_notes) {
......@@ -3900,35 +3898,28 @@ pub fn ptraceDetach(self: *MachO, pid: std.posix.pid_t) !void {
39003898 self.hot_state.mach_task = null;
39013899}
39023900
3903pub fn dumpState(self: *MachO) std.fmt.Formatter(fmtDumpState) {
3901pub fn dumpState(self: *MachO) std.fmt.Formatter(*MachO, fmtDumpState) {
39043902 return .{ .data = self };
39053903}
39063904
3907fn fmtDumpState(
3908 self: *MachO,
3909 comptime unused_fmt_string: []const u8,
3910 options: std.fmt.FormatOptions,
3911 writer: anytype,
3912) !void {
3913 _ = options;
3914 _ = unused_fmt_string;
3905fn fmtDumpState(self: *MachO, w: *Writer) Writer.Error!void {
39153906 if (self.getZigObject()) |zo| {
3916 try writer.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename });
3917 try writer.print("{}{}\n", .{
3907 try w.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename });
3908 try w.print("{f}{f}\n", .{
39183909 zo.fmtAtoms(self),
39193910 zo.fmtSymtab(self),
39203911 });
39213912 }
39223913 for (self.objects.items) |index| {
39233914 const object = self.getFile(index).?.object;
3924 try writer.print("object({d}) : {} : has_debug({})", .{
3915 try w.print("object({d}) : {f} : has_debug({})", .{
39253916 index,
39263917 object.fmtPath(),
39273918 object.hasDebugInfo(),
39283919 });
3929 if (!object.alive) try writer.writeAll(" : ([*])");
3930 try writer.writeByte('\n');
3931 try writer.print("{}{}{}{}{}\n", .{
3920 if (!object.alive) try w.writeAll(" : ([*])");
3921 try w.writeByte('\n');
3922 try w.print("{f}{f}{f}{f}{f}\n", .{
39323923 object.fmtAtoms(self),
39333924 object.fmtCies(self),
39343925 object.fmtFdes(self),
......@@ -3938,48 +3929,41 @@ fn fmtDumpState(
39383929 }
39393930 for (self.dylibs.items) |index| {
39403931 const dylib = self.getFile(index).?.dylib;
3941 try writer.print("dylib({d}) : {} : needed({}) : weak({})", .{
3932 try w.print("dylib({d}) : {f} : needed({}) : weak({})", .{
39423933 index,
39433934 @as(Path, dylib.path),
39443935 dylib.needed,
39453936 dylib.weak,
39463937 });
3947 if (!dylib.isAlive(self)) try writer.writeAll(" : ([*])");
3948 try writer.writeByte('\n');
3949 try writer.print("{}\n", .{dylib.fmtSymtab(self)});
3938 if (!dylib.isAlive(self)) try w.writeAll(" : ([*])");
3939 try w.writeByte('\n');
3940 try w.print("{f}\n", .{dylib.fmtSymtab(self)});
39503941 }
39513942 if (self.getInternalObject()) |internal| {
3952 try writer.print("internal({d}) : internal\n", .{internal.index});
3953 try writer.print("{}{}\n", .{ internal.fmtAtoms(self), internal.fmtSymtab(self) });
3943 try w.print("internal({d}) : internal\n", .{internal.index});
3944 try w.print("{f}{f}\n", .{ internal.fmtAtoms(self), internal.fmtSymtab(self) });
39543945 }
3955 try writer.writeAll("thunks\n");
3946 try w.writeAll("thunks\n");
39563947 for (self.thunks.items, 0..) |thunk, index| {
3957 try writer.print("thunk({d}) : {}\n", .{ index, thunk.fmt(self) });
3948 try w.print("thunk({d}) : {f}\n", .{ index, thunk.fmt(self) });
39583949 }
3959 try writer.print("stubs\n{}\n", .{self.stubs.fmt(self)});
3960 try writer.print("objc_stubs\n{}\n", .{self.objc_stubs.fmt(self)});
3961 try writer.print("got\n{}\n", .{self.got.fmt(self)});
3962 try writer.print("tlv_ptr\n{}\n", .{self.tlv_ptr.fmt(self)});
3963 try writer.writeByte('\n');
3964 try writer.print("sections\n{}\n", .{self.fmtSections()});
3965 try writer.print("segments\n{}\n", .{self.fmtSegments()});
3950 try w.print("stubs\n{f}\n", .{self.stubs.fmt(self)});
3951 try w.print("objc_stubs\n{f}\n", .{self.objc_stubs.fmt(self)});
3952 try w.print("got\n{f}\n", .{self.got.fmt(self)});
3953 try w.print("tlv_ptr\n{f}\n", .{self.tlv_ptr.fmt(self)});
3954 try w.writeByte('\n');
3955 try w.print("sections\n{f}\n", .{self.fmtSections()});
3956 try w.print("segments\n{f}\n", .{self.fmtSegments()});
39663957}
39673958
3968fn fmtSections(self: *MachO) std.fmt.Formatter(formatSections) {
3959fn fmtSections(self: *MachO) std.fmt.Formatter(*MachO, formatSections) {
39693960 return .{ .data = self };
39703961}
39713962
3972fn formatSections(
3973 self: *MachO,
3974 comptime unused_fmt_string: []const u8,
3975 options: std.fmt.FormatOptions,
3976 writer: anytype,
3977) !void {
3978 _ = options;
3979 _ = unused_fmt_string;
3963fn formatSections(self: *MachO, w: *Writer) Writer.Error!void {
39803964 const slice = self.sections.slice();
39813965 for (slice.items(.header), slice.items(.segment_id), 0..) |header, seg_id, i| {
3982 try writer.print(
3966 try w.print(
39833967 "sect({d}) : seg({d}) : {s},{s} : @{x} ({x}) : align({x}) : size({x}) : relocs({x};{d})\n",
39843968 .{
39853969 i, seg_id, header.segName(), header.sectName(), header.addr, header.offset,
......@@ -3989,38 +3973,24 @@ fn formatSections(
39893973 }
39903974}
39913975
3992fn fmtSegments(self: *MachO) std.fmt.Formatter(formatSegments) {
3976fn fmtSegments(self: *MachO) std.fmt.Formatter(*MachO, formatSegments) {
39933977 return .{ .data = self };
39943978}
39953979
3996fn formatSegments(
3997 self: *MachO,
3998 comptime unused_fmt_string: []const u8,
3999 options: std.fmt.FormatOptions,
4000 writer: anytype,
4001) !void {
4002 _ = options;
4003 _ = unused_fmt_string;
3980fn formatSegments(self: *MachO, w: *Writer) Writer.Error!void {
40043981 for (self.segments.items, 0..) |seg, i| {
4005 try writer.print("seg({d}) : {s} : @{x}-{x} ({x}-{x})\n", .{
3982 try w.print("seg({d}) : {s} : @{x}-{x} ({x}-{x})\n", .{
40063983 i, seg.segName(), seg.vmaddr, seg.vmaddr + seg.vmsize,
40073984 seg.fileoff, seg.fileoff + seg.filesize,
40083985 });
40093986 }
40103987}
40113988
4012pub fn fmtSectType(tt: u8) std.fmt.Formatter(formatSectType) {
3989pub fn fmtSectType(tt: u8) std.fmt.Formatter(u8, formatSectType) {
40133990 return .{ .data = tt };
40143991}
40153992
4016fn formatSectType(
4017 tt: u8,
4018 comptime unused_fmt_string: []const u8,
4019 options: std.fmt.FormatOptions,
4020 writer: anytype,
4021) !void {
4022 _ = options;
4023 _ = unused_fmt_string;
3993fn formatSectType(tt: u8, w: *Writer) Writer.Error!void {
40243994 const name = switch (tt) {
40253995 macho.S_REGULAR => "REGULAR",
40263996 macho.S_ZEROFILL => "ZEROFILL",
......@@ -4044,9 +4014,9 @@ fn formatSectType(
40444014 macho.S_THREAD_LOCAL_VARIABLE_POINTERS => "THREAD_LOCAL_VARIABLE_POINTERS",
40454015 macho.S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => "THREAD_LOCAL_INIT_FUNCTION_POINTERS",
40464016 macho.S_INIT_FUNC_OFFSETS => "INIT_FUNC_OFFSETS",
4047 else => |x| return writer.print("UNKNOWN({x})", .{x}),
4017 else => |x| return w.print("UNKNOWN({x})", .{x}),
40484018 };
4049 try writer.print("{s}", .{name});
4019 try w.print("{s}", .{name});
40504020}
40514021
40524022const is_hot_update_compatible = switch (builtin.target.os.tag) {
......@@ -4058,7 +4028,7 @@ const default_entry_symbol_name = "_main";
40584028
40594029const Section = struct {
40604030 header: macho.section_64,
4061 segment_id: u8,
4031 segment_id: u4,
40624032 atoms: std.ArrayListUnmanaged(Ref) = .empty,
40634033 free_list: std.ArrayListUnmanaged(Atom.Index) = .empty,
40644034 last_atom_index: Atom.Index = 0,
......@@ -4279,28 +4249,21 @@ pub const Platform = struct {
42794249 return false;
42804250 }
42814251
4282 pub fn fmtTarget(plat: Platform, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(formatTarget) {
4252 pub fn fmtTarget(plat: Platform, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(Format, Format.target) {
42834253 return .{ .data = .{ .platform = plat, .cpu_arch = cpu_arch } };
42844254 }
42854255
4286 const FmtCtx = struct {
4256 const Format = struct {
42874257 platform: Platform,
42884258 cpu_arch: std.Target.Cpu.Arch,
4289 };
42904259
4291 pub fn formatTarget(
4292 ctx: FmtCtx,
4293 comptime unused_fmt_string: []const u8,
4294 options: std.fmt.FormatOptions,
4295 writer: anytype,
4296 ) !void {
4297 _ = unused_fmt_string;
4298 _ = options;
4299 try writer.print("{s}-{s}", .{ @tagName(ctx.cpu_arch), @tagName(ctx.platform.os_tag) });
4300 if (ctx.platform.abi != .none) {
4301 try writer.print("-{s}", .{@tagName(ctx.platform.abi)});
4260 pub fn target(f: Format, w: *Writer) Writer.Error!void {
4261 try w.print("{s}-{s}", .{ @tagName(f.cpu_arch), @tagName(f.platform.os_tag) });
4262 if (f.platform.abi != .none) {
4263 try w.print("-{s}", .{@tagName(f.platform.abi)});
4264 }
43024265 }
4303 }
4266 };
43044267
43054268 /// Caller owns the memory.
43064269 pub fn allocPrintTarget(plat: Platform, gpa: Allocator, cpu_arch: std.Target.Cpu.Arch) error{OutOfMemory}![]u8 {
......@@ -4390,7 +4353,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
43904353// The file/property is also available with vendored libc.
43914354fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {
43924355 const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" });
4393 const contents = try fs.cwd().readFileAlloc(arena, sdk_path, std.math.maxInt(u16));
4356 const contents = try fs.cwd().readFileAlloc(sdk_path, arena, .limited(std.math.maxInt(u16)));
43944357 const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});
43954358 if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;
43964359 return error.SdkVersionFailure;
......@@ -4406,7 +4369,7 @@ fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion {
44064369 };
44074370
44084371 const parseNext = struct {
4409 fn parseNext(it: anytype) ?u16 {
4372 fn parseNext(it: *std.mem.SplitIterator(u8, .any)) ?u16 {
44104373 const nn = it.next() orelse return null;
44114374 return std.fmt.parseInt(u16, nn, 10) catch null;
44124375 }
......@@ -4507,15 +4470,9 @@ pub const Ref = struct {
45074470 };
45084471 }
45094472
4510 pub fn format(
4511 ref: Ref,
4512 comptime unused_fmt_string: []const u8,
4513 options: std.fmt.FormatOptions,
4514 writer: anytype,
4515 ) !void {
4516 _ = unused_fmt_string;
4517 _ = options;
4518 try writer.print("%{d} in file({d})", .{ ref.index, ref.file });
4473 pub fn format(ref: Ref, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void {
4474 comptime assert(unused_fmt_string.len == 0);
4475 try bw.print("%{d} in file({d})", .{ ref.index, ref.file });
45194476 }
45204477};
45214478
......@@ -5315,7 +5272,7 @@ fn createThunks(macho_file: *MachO, sect_id: u8) !void {
53155272 try scanThunkRelocs(thunk_index, gpa, atoms[start..i], macho_file);
53165273 thunk.value = advanceSection(header, thunk.size(), .@"4");
53175274
5318 log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) });
5275 log.debug("thunk({d}) : {f}", .{ thunk_index, thunk.fmt(macho_file) });
53195276 }
53205277}
53215278
......@@ -5360,8 +5317,11 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
53605317pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void {
53615318 const comp = macho_file.base.comp;
53625319 const diags = &comp.link_diags;
5363 macho_file.base.file.?.pwriteAll(bytes, offset) catch |err| {
5364 return diags.fail("failed to write: {s}", .{@errorName(err)});
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.?)}),
53655325 };
53665326}
53675327
......@@ -5414,6 +5374,7 @@ const macho = std.macho;
54145374const math = std.math;
54155375const mem = std.mem;
54165376const meta = std.meta;
5377const Writer = std.io.Writer;
54175378
54185379const aarch64 = @import("../arch/aarch64/bits.zig");
54195380const bind = @import("MachO/dyld_info/bind.zig");
src/link/MachO/Archive.zig+36-69
......@@ -71,53 +71,29 @@ 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 '{}' from archive '{}'", .{ object.path, path });
74 log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path });
7575
7676 try self.objects.append(gpa, object);
7777 }
7878}
7979
8080pub fn writeHeader(
81 bw: *Writer,
8182 object_name: []const u8,
8283 object_size: usize,
8384 format: Format,
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 }
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';
10089 @memcpy(&hdr.ar_fmag, ARFMAG);
101
10290 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;
10392 const total_object_size = object_size + 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 }
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);
12197}
12298
12399// Archive files start with the ARMAG identifying string. Then follows a
......@@ -201,12 +177,12 @@ pub const ArSymtab = struct {
201177 return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
202178 }
203179
204 pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: anytype) !void {
180 pub fn write(ar: ArSymtab, bw: *Writer, format: Format, macho_file: *MachO) Writer.Error!void {
205181 const ptr_width = ptrWidth(format);
206182 // Header
207 try writeHeader(SYMDEF, ar.size(format), format, writer);
183 try writeHeader(bw, SYMDEF, ar.size(format), format);
208184 // Symtab size
209 try writeInt(format, ar.entries.items.len * 2 * ptr_width, writer);
185 try writeInt(bw, format, ar.entries.items.len * 2 * ptr_width);
210186 // Symtab entries
211187 for (ar.entries.items) |entry| {
212188 const file_off = switch (macho_file.getFile(entry.file).?) {
......@@ -215,47 +191,37 @@ pub const ArSymtab = struct {
215191 else => unreachable,
216192 };
217193 // Name offset
218 try writeInt(format, entry.off, writer);
194 try writeInt(bw, format, entry.off);
219195 // File offset
220 try writeInt(format, file_off, writer);
196 try writeInt(bw, format, file_off);
221197 }
222198 // Strtab size
223199 const strtab_size = mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
224 const padding = strtab_size - ar.strtab.buffer.items.len;
225 try writeInt(format, strtab_size, writer);
200 try writeInt(bw, format, strtab_size);
226201 // Strtab
227 try writer.writeAll(ar.strtab.buffer.items);
228 if (padding > 0) {
229 try writer.writeByteNTimes(0, padding);
230 }
202 try bw.writeAll(ar.strtab.buffer.items);
203 try bw.splatByteAll(0, strtab_size - ar.strtab.buffer.items.len);
231204 }
232205
233 const FormatContext = struct {
206 const PrintFormat = struct {
234207 ar: ArSymtab,
235208 macho_file: *MachO,
209
210 fn default(f: PrintFormat, bw: *Writer) Writer.Error!void {
211 const ar = f.ar;
212 const macho_file = f.macho_file;
213 for (ar.entries.items, 0..) |entry, i| {
214 const name = ar.strtab.getAssumeExists(entry.off);
215 const file = macho_file.getFile(entry.file).?;
216 try bw.print(" {d}: {s} in file({d})({f})\n", .{ i, name, entry.file, file.fmtPath() });
217 }
218 }
236219 };
237220
238 pub fn fmt(ar: ArSymtab, macho_file: *MachO) std.fmt.Formatter(format2) {
221 pub fn fmt(ar: ArSymtab, macho_file: *MachO) std.fmt.Formatter(PrintFormat, PrintFormat.default) {
239222 return .{ .data = .{ .ar = ar, .macho_file = macho_file } };
240223 }
241224
242 fn format2(
243 ctx: FormatContext,
244 comptime unused_fmt_string: []const u8,
245 options: std.fmt.FormatOptions,
246 writer: anytype,
247 ) !void {
248 _ = unused_fmt_string;
249 _ = options;
250 const ar = ctx.ar;
251 const macho_file = ctx.macho_file;
252 for (ar.entries.items, 0..) |entry, i| {
253 const name = ar.strtab.getAssumeExists(entry.off);
254 const file = macho_file.getFile(entry.file).?;
255 try writer.print(" {d}: {s} in file({d})({})\n", .{ i, name, entry.file, file.fmtPath() });
256 }
257 }
258
259225 const Entry = struct {
260226 /// Symbol name offset
261227 off: u32,
......@@ -282,10 +248,10 @@ pub fn ptrWidth(format: Format) usize {
282248 };
283249}
284250
285pub fn writeInt(format: Format, value: u64, writer: anytype) !void {
251pub fn writeInt(bw: *Writer, format: Format, value: u64) Writer.Error!void {
286252 switch (format) {
287 .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
288 .p64 => try writer.writeInt(u64, value, .little),
253 .p32 => try bw.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
254 .p64 => try bw.writeInt(u64, value, .little),
289255 }
290256}
291257
......@@ -304,8 +270,9 @@ const log = std.log.scoped(.link);
304270const macho = std.macho;
305271const mem = std.mem;
306272const std = @import("std");
307const Allocator = mem.Allocator;
273const Allocator = std.mem.Allocator;
308274const Path = std.Build.Cache.Path;
275const Writer = std.io.Writer;
309276
310277const Archive = @This();
311278const File = @import("file.zig").File;
src/link/MachO/Atom.zig+78-101
......@@ -580,8 +580,9 @@ 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
583585 var has_error = false;
584 var stream = std.io.fixedBufferStream(buffer);
585586 var i: usize = 0;
586587 while (i < relocs.len) : (i += 1) {
587588 const rel = relocs[i];
......@@ -592,30 +593,28 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
592593 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;
593594 }
594595
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 }
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,
619618 };
620619 }
621620
......@@ -638,8 +637,8 @@ fn resolveRelocInner(
638637 subtractor: ?Relocation,
639638 code: []u8,
640639 macho_file: *MachO,
641 writer: anytype,
642) ResolveError!void {
640 bw: *Writer,
641) Writer.Error!void {
643642 const t = &macho_file.base.comp.root_mod.resolved_target.result;
644643 const cpu_arch = t.cpu.arch;
645644 const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;
......@@ -653,7 +652,7 @@ fn resolveRelocInner(
653652 const divExact = struct {
654653 fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {
655654 return math.divExact(u12, num, den) catch {
656 try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {s} at offset 0x{x}", .{
655 try ctx.reportParseError2(atom.getFile(ctx).getIndex(), "{s}: unexpected remainder when resolving {f} at offset 0x{x}", .{
657656 atom.getName(ctx),
658657 r.fmtPretty(ctx.getTarget().cpu.arch),
659658 r.offset,
......@@ -664,14 +663,14 @@ fn resolveRelocInner(
664663 }.divExact;
665664
666665 switch (rel.tag) {
667 .local => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] atom({d})", .{
666 .local => relocs_log.debug(" {x}<+{d}>: {f}: [=> {x}] atom({d})", .{
668667 P,
669668 rel_offset,
670669 rel.fmtPretty(cpu_arch),
671670 S + A - SUB,
672671 rel.getTargetAtom(self, macho_file).atom_index,
673672 }),
674 .@"extern" => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] G({x}) ({s})", .{
673 .@"extern" => relocs_log.debug(" {x}<+{d}>: {f}: [=> {x}] G({x}) ({s})", .{
675674 P,
676675 rel_offset,
677676 rel.fmtPretty(cpu_arch),
......@@ -690,14 +689,14 @@ fn resolveRelocInner(
690689 if (rel.tag == .@"extern") {
691690 const sym = rel.getTargetSymbol(self, macho_file);
692691 if (sym.isTlvInit(macho_file)) {
693 try writer.writeInt(u64, @intCast(S - TLS), .little);
692 try bw.writeInt(u64, @intCast(S - TLS), .little);
694693 return;
695694 }
696695 if (sym.flags.import) return;
697696 }
698 try writer.writeInt(u64, @bitCast(S + A - SUB), .little);
697 try bw.writeInt(u64, @bitCast(S + A - SUB), .little);
699698 } else if (rel.meta.length == 2) {
700 try writer.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little);
699 try bw.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little);
701700 } else unreachable;
702701 },
703702
......@@ -705,7 +704,7 @@ fn resolveRelocInner(
705704 assert(rel.tag == .@"extern");
706705 assert(rel.meta.length == 2);
707706 assert(rel.meta.pcrel);
708 try writer.writeInt(i32, @intCast(G + A - P), .little);
707 try bw.writeInt(i32, @intCast(G + A - P), .little);
709708 },
710709
711710 .branch => {
......@@ -714,7 +713,7 @@ fn resolveRelocInner(
714713 assert(rel.tag == .@"extern");
715714
716715 switch (cpu_arch) {
717 .x86_64 => try writer.writeInt(i32, @intCast(S + A - P), .little),
716 .x86_64 => try bw.writeInt(i32, @intCast(S + A - P), .little),
718717 .aarch64 => {
719718 const disp: i28 = math.cast(i28, S + A - P) orelse blk: {
720719 const thunk = self.getThunk(macho_file);
......@@ -732,10 +731,10 @@ fn resolveRelocInner(
732731 assert(rel.meta.length == 2);
733732 assert(rel.meta.pcrel);
734733 if (rel.getTargetSymbol(self, macho_file).getSectionFlags().has_got) {
735 try writer.writeInt(i32, @intCast(G + A - P), .little);
734 try bw.writeInt(i32, @intCast(G + A - P), .little);
736735 } else {
737736 try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file);
738 try writer.writeInt(i32, @intCast(S + A - P), .little);
737 try bw.writeInt(i32, @intCast(S + A - P), .little);
739738 }
740739 },
741740
......@@ -746,17 +745,17 @@ fn resolveRelocInner(
746745 const sym = rel.getTargetSymbol(self, macho_file);
747746 if (sym.getSectionFlags().tlv_ptr) {
748747 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));
749 try writer.writeInt(i32, @intCast(S_ + A - P), .little);
748 try bw.writeInt(i32, @intCast(S_ + A - P), .little);
750749 } else {
751750 try x86_64.relaxTlv(code[rel_offset - 3 ..], t);
752 try writer.writeInt(i32, @intCast(S + A - P), .little);
751 try bw.writeInt(i32, @intCast(S + A - P), .little);
753752 }
754753 },
755754
756755 .signed, .signed1, .signed2, .signed4 => {
757756 assert(rel.meta.length == 2);
758757 assert(rel.meta.pcrel);
759 try writer.writeInt(i32, @intCast(S + A - P), .little);
758 try bw.writeInt(i32, @intCast(S + A - P), .little);
760759 },
761760
762761 .page,
......@@ -808,7 +807,7 @@ fn resolveRelocInner(
808807 2 => try divExact(self, rel, @truncate(target), 4, macho_file),
809808 3 => try divExact(self, rel, @truncate(target), 8, macho_file),
810809 };
811 try writer.writeInt(u32, inst.toU32(), .little);
810 try bw.writeInt(u32, inst.toU32(), .little);
812811 }
813812 },
814813
......@@ -886,7 +885,7 @@ fn resolveRelocInner(
886885 .sf = @as(u1, @truncate(reg_info.size)),
887886 },
888887 };
889 try writer.writeInt(u32, inst.toU32(), .little);
888 try bw.writeInt(u32, inst.toU32(), .little);
890889 },
891890 }
892891}
......@@ -900,19 +899,19 @@ const x86_64 = struct {
900899 switch (old_inst.encoding.mnemonic) {
901900 .mov => {
902901 const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops, t) catch return error.RelaxFail;
903 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
902 relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding });
904903 encode(&.{inst}, code) catch return error.RelaxFail;
905904 },
906905 else => |x| {
907906 var err = try diags.addErrorWithNotes(2);
908 try err.addMsg("{s}: 0x{x}: 0x{x}: failed to relax relocation of type {}", .{
907 try err.addMsg("{s}: 0x{x}: 0x{x}: failed to relax relocation of type {f}", .{
909908 self.getName(macho_file),
910909 self.getAddress(macho_file),
911910 rel.offset,
912911 rel.fmtPretty(.x86_64),
913912 });
914913 err.addNote("expected .mov instruction but found .{s}", .{@tagName(x)});
915 err.addNote("while parsing {}", .{self.getFile(macho_file).fmtPath()});
914 err.addNote("while parsing {f}", .{self.getFile(macho_file).fmtPath()});
916915 return error.RelaxFailUnexpectedInstruction;
917916 },
918917 }
......@@ -924,7 +923,7 @@ const x86_64 = struct {
924923 switch (old_inst.encoding.mnemonic) {
925924 .mov => {
926925 const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops, t) catch return error.RelaxFail;
927 relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
926 relocs_log.debug(" relaxing {f} => {f}", .{ old_inst.encoding, inst.encoding });
928927 encode(&.{inst}, code) catch return error.RelaxFail;
929928 },
930929 else => return error.RelaxFail,
......@@ -938,11 +937,8 @@ const x86_64 = struct {
938937 }
939938
940939 fn encode(insts: []const Instruction, code: []u8) !void {
941 var stream = std.io.fixedBufferStream(code);
942 const writer = stream.writer();
943 for (insts) |inst| {
944 try inst.encode(writer, .{});
945 }
940 var bw: Writer = .fixed(code);
941 for (insts) |inst| try inst.encode(&bw, .{});
946942 }
947943
948944 const bits = @import("../../arch/x86_64/bits.zig");
......@@ -1003,7 +999,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
1003999 }
10041000
10051001 switch (rel.tag) {
1006 .local => relocs_log.debug(" {}: [{x} => {d}({s},{s})] + {x}", .{
1002 .local => relocs_log.debug(" {f}: [{x} => {d}({s},{s})] + {x}", .{
10071003 rel.fmtPretty(cpu_arch),
10081004 r_address,
10091005 r_symbolnum,
......@@ -1011,7 +1007,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
10111007 macho_file.sections.items(.header)[r_symbolnum - 1].sectName(),
10121008 addend,
10131009 }),
1014 .@"extern" => relocs_log.debug(" {}: [{x} => {d}({s})] + {x}", .{
1010 .@"extern" => relocs_log.debug(" {f}: [{x} => {d}({s})] + {x}", .{
10151011 rel.fmtPretty(cpu_arch),
10161012 r_address,
10171013 r_symbolnum,
......@@ -1117,60 +1113,40 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
11171113 assert(i == buffer.len);
11181114}
11191115
1120pub fn format(
1121 atom: Atom,
1122 comptime unused_fmt_string: []const u8,
1123 options: std.fmt.FormatOptions,
1124 writer: anytype,
1125) !void {
1126 _ = atom;
1127 _ = unused_fmt_string;
1128 _ = options;
1129 _ = writer;
1130 @compileError("do not format Atom directly");
1131}
1132
1133pub fn fmt(atom: Atom, macho_file: *MachO) std.fmt.Formatter(format2) {
1116pub fn fmt(atom: Atom, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
11341117 return .{ .data = .{
11351118 .atom = atom,
11361119 .macho_file = macho_file,
11371120 } };
11381121}
11391122
1140const FormatContext = struct {
1123const Format = struct {
11411124 atom: Atom,
11421125 macho_file: *MachO,
1143};
11441126
1145fn format2(
1146 ctx: FormatContext,
1147 comptime unused_fmt_string: []const u8,
1148 options: std.fmt.FormatOptions,
1149 writer: anytype,
1150) !void {
1151 _ = options;
1152 _ = unused_fmt_string;
1153 const atom = ctx.atom;
1154 const macho_file = ctx.macho_file;
1155 const file = atom.getFile(macho_file);
1156 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{
1157 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),
1158 atom.out_n_sect, atom.alignment, atom.size,
1159 atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk,
1160 });
1161 if (!atom.isAlive()) try writer.writeAll(" : [*]");
1162 if (atom.getUnwindRecords(macho_file).len > 0) {
1163 try writer.writeAll(" : unwind{ ");
1164 const extra = atom.getExtra(macho_file);
1165 for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| {
1166 const rec = file.object.getUnwindRecord(index);
1167 try writer.print("{d}", .{index});
1168 if (!rec.alive) try writer.writeAll("([*])");
1169 if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", ");
1127 fn print(f: Format, w: *Writer) Writer.Error!void {
1128 const atom = f.atom;
1129 const macho_file = f.macho_file;
1130 const file = atom.getFile(macho_file);
1131 try w.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{
1132 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),
1133 atom.out_n_sect, atom.alignment, atom.size,
1134 atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk,
1135 });
1136 if (!atom.isAlive()) try w.writeAll(" : [*]");
1137 if (atom.getUnwindRecords(macho_file).len > 0) {
1138 try w.writeAll(" : unwind{ ");
1139 const extra = atom.getExtra(macho_file);
1140 for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| {
1141 const rec = file.object.getUnwindRecord(index);
1142 try w.print("{d}", .{index});
1143 if (!rec.alive) try w.writeAll("([*])");
1144 if (i < extra.unwind_index + extra.unwind_count - 1) try w.writeAll(", ");
1145 }
1146 try w.writeAll(" }");
11701147 }
1171 try writer.writeAll(" }");
11721148 }
1173}
1149};
11741150
11751151pub const Index = u32;
11761152
......@@ -1205,19 +1181,20 @@ pub const Extra = struct {
12051181
12061182pub const Alignment = @import("../../InternPool.zig").Alignment;
12071183
1208const aarch64 = @import("../aarch64.zig");
1184const std = @import("std");
12091185const assert = std.debug.assert;
12101186const macho = std.macho;
12111187const math = std.math;
12121188const mem = std.mem;
12131189const log = std.log.scoped(.link);
12141190const relocs_log = std.log.scoped(.link_relocs);
1215const std = @import("std");
1216const trace = @import("../../tracy.zig").trace;
1217
1191const Writer = std.io.Writer;
12181192const Allocator = mem.Allocator;
1219const Atom = @This();
12201193const AtomicBool = std.atomic.Value(bool);
1194
1195const aarch64 = @import("../aarch64.zig");
1196const trace = @import("../../tracy.zig").trace;
1197const Atom = @This();
12211198const File = @import("file.zig").File;
12221199const MachO = @import("../MachO.zig");
12231200const Object = @import("Object.zig");
src/link/MachO/CodeSignature.zig+11-9
......@@ -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, std.math.maxInt(u32));
250 const inner = try file.readToEndAlloc(allocator, .unlimited);
251251 self.entitlements = .{ .inner = inner };
252252}
253253
......@@ -304,10 +304,11 @@ pub fn writeAdhocSignature(
304304 var hash: [hash_size]u8 = undefined;
305305
306306 if (self.requirements) |*req| {
307 var buf = std.ArrayList(u8).init(allocator);
308 defer buf.deinit();
309 try req.write(buf.writer());
310 Sha256.hash(buf.items, &hash, .{});
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, .{});
311312 self.code_directory.addSpecialHash(req.slotType(), hash);
312313
313314 try blobs.append(.{ .requirements = req });
......@@ -316,10 +317,11 @@ pub fn writeAdhocSignature(
316317 }
317318
318319 if (self.entitlements) |*ents| {
319 var buf = std.ArrayList(u8).init(allocator);
320 defer buf.deinit();
321 try ents.write(buf.writer());
322 Sha256.hash(buf.items, &hash, .{});
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, .{});
323325 self.code_directory.addSpecialHash(ents.slotType(), hash);
324326
325327 try blobs.append(.{ .entitlements = ents });
src/link/MachO/DebugSymbols.zig+12-16
......@@ -269,18 +269,14 @@ 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 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();
272 var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeDsym(macho_file, self)));
273 defer gpa.free(bw.buffer);
278274
279275 var ncmds: usize = 0;
280276
281277 // UUID comes first presumably to speed up lookup by the consumer like lldb.
282278 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);
283 try writer.writeStruct(self.uuid_cmd);
279 try bw.writeStruct(self.uuid_cmd);
284280 ncmds += 1;
285281
286282 // Segment and section load commands
......@@ -293,11 +289,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
293289 var out_seg = seg;
294290 out_seg.fileoff = 0;
295291 out_seg.filesize = 0;
296 try writer.writeStruct(out_seg);
292 try bw.writeStruct(out_seg);
297293 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
298294 var out_header = header;
299295 out_header.offset = 0;
300 try writer.writeStruct(out_header);
296 try bw.writeStruct(out_header);
301297 }
302298 sect_id += seg.nsects;
303299 }
......@@ -306,23 +302,22 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
306302 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
307303 sect_id = 0;
308304 for (self.segments.items) |seg| {
309 try writer.writeStruct(seg);
305 try bw.writeStruct(seg);
310306 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
311 try writer.writeStruct(header);
307 try bw.writeStruct(header);
312308 }
313309 sect_id += seg.nsects;
314310 }
315311 ncmds += self.segments.items.len;
316312 }
317313
318 try writer.writeStruct(self.symtab_cmd);
314 try bw.writeStruct(self.symtab_cmd);
319315 ncmds += 1;
320316
321 assert(stream.pos == needed_size);
322
323 try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
317 assert(bw.end == bw.buffer.len);
318 try self.file.?.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
324319
325 return .{ ncmds, buffer.len };
320 return .{ ncmds, bw.end };
326321}
327322
328323fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
......@@ -460,6 +455,7 @@ const math = std.math;
460455const mem = std.mem;
461456const padToIdeal = MachO.padToIdeal;
462457const trace = @import("../../tracy.zig").trace;
458const Writer = std.io.Writer;
463459
464460const Allocator = mem.Allocator;
465461const MachO = @import("../MachO.zig");
src/link/MachO/Dwarf.zig+18-30
......@@ -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.readUleb128(u64);
84 const di_code = try p.readLeb128(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.readUleb128(u64),
177 dw.FORM.block => try p.readLeb128(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.readUleb128(u64);
184 const len: u64 = try p.readLeb128(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.readUleb128(u64),
195 dw.FORM.sdata => @bitCast(try p.readIleb128(i64)),
194 dw.FORM.udata, dw.FORM.ref_udata => try p.readLeb128(u64),
195 dw.FORM.sdata => @bitCast(try p.readLeb128(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.readUleb128(u64),
206 dw.FORM.strx, dw.FORM.addrx => try p.readLeb128(u64),
207207 else => return error.UnhandledIndexForm,
208208 };
209209 }
......@@ -272,20 +272,10 @@ pub const InfoReader = struct {
272272 };
273273 }
274274
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;
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);
289279 }
290280
291281 pub fn seekTo(p: *InfoReader, off: u64) !void {
......@@ -307,10 +297,10 @@ pub const AbbrevReader = struct {
307297
308298 pub fn readDecl(p: *AbbrevReader) !?AbbrevDecl {
309299 const pos = p.pos;
310 const code = try p.readUleb128(Code);
300 const code = try p.readLeb128(Code);
311301 if (code == 0) return null;
312302
313 const tag = try p.readUleb128(Tag);
303 const tag = try p.readLeb128(Tag);
314304 const has_children = (try p.readByte()) > 0;
315305 return .{
316306 .code = code,
......@@ -323,8 +313,8 @@ pub const AbbrevReader = struct {
323313
324314 pub fn readAttr(p: *AbbrevReader) !?AbbrevAttr {
325315 const pos = p.pos;
326 const at = try p.readUleb128(At);
327 const form = try p.readUleb128(Form);
316 const at = try p.readLeb128(At);
317 const form = try p.readLeb128(Form);
328318 return if (at == 0 and form == 0) null else .{
329319 .at = at,
330320 .form = form,
......@@ -339,12 +329,10 @@ pub const AbbrevReader = struct {
339329 return p.bytes()[p.pos];
340330 }
341331
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;
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);
348336 }
349337
350338 pub fn seekTo(p: *AbbrevReader, off: u64) !void {
src/link/MachO/Dylib.zig+41-101
......@@ -61,7 +61,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
6161 const file = macho_file.getFileHandle(self.file_handle);
6262 const offset = self.offset;
6363
64 log.debug("parsing dylib from binary: {}", .{@as(Path, self.path)});
64 log.debug("parsing dylib from binary: {f}", .{@as(Path, self.path)});
6565
6666 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
6767 {
......@@ -140,7 +140,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
140140
141141 if (self.platform) |platform| {
142142 if (!macho_file.platform.eqlTarget(platform)) {
143 try macho_file.reportParseError2(self.index, "invalid platform: {}", .{
143 try macho_file.reportParseError2(self.index, "invalid platform: {f}", .{
144144 platform.fmtTarget(macho_file.getTarget().cpu.arch),
145145 });
146146 return error.InvalidTarget;
......@@ -148,7 +148,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
148148 // TODO: this can cause the CI to fail so I'm commenting this check out so that
149149 // I can work out the rest of the changes first
150150 // if (macho_file.platform.version.order(platform.version) == .lt) {
151 // try macho_file.reportParseError2(self.index, "object file built for newer platform: {}: {} < {}", .{
151 // try macho_file.reportParseError2(self.index, "object file built for newer platform: {f}: {f} < {f}", .{
152152 // macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),
153153 // macho_file.platform.version,
154154 // platform.version,
......@@ -158,46 +158,6 @@ 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
201161pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void {
202162 try self.exports.append(allocator, .{
203163 .name = try self.addString(allocator, name),
......@@ -207,16 +167,16 @@ pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Ex
207167
208168fn parseTrieNode(
209169 self: *Dylib,
210 it: *TrieIterator,
170 br: *std.io.Reader,
211171 allocator: Allocator,
212172 arena: Allocator,
213173 prefix: []const u8,
214174) !void {
215175 const tracy = trace(@src());
216176 defer tracy.end();
217 const size = try it.readUleb128();
177 const size = try br.takeLeb128(u64);
218178 if (size > 0) {
219 const flags = try it.readUleb128();
179 const flags = try br.takeLeb128(u8);
220180 const kind = flags & macho.EXPORT_SYMBOL_FLAGS_KIND_MASK;
221181 const out_flags = Export.Flags{
222182 .abs = kind == macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE,
......@@ -224,29 +184,28 @@ fn parseTrieNode(
224184 .weak = flags & macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION != 0,
225185 };
226186 if (flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT != 0) {
227 _ = try it.readUleb128(); // dylib ordinal
228 const name = try it.readString();
187 _ = try br.takeLeb128(u64); // dylib ordinal
188 const name = try br.takeSentinel(0);
229189 try self.addExport(allocator, if (name.len > 0) name else prefix, out_flags);
230190 } else if (flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER != 0) {
231 _ = try it.readUleb128(); // stub offset
232 _ = try it.readUleb128(); // resolver offset
191 _ = try br.takeLeb128(u64); // stub offset
192 _ = try br.takeLeb128(u64); // resolver offset
233193 try self.addExport(allocator, prefix, out_flags);
234194 } else {
235 _ = try it.readUleb128(); // VM offset
195 _ = try br.takeLeb128(u64); // VM offset
236196 try self.addExport(allocator, prefix, out_flags);
237197 }
238198 }
239199
240 const nedges = try it.readByte();
241
200 const nedges = try br.takeByte();
242201 for (0..nedges) |_| {
243 const label = try it.readString();
244 const off = try it.readUleb128();
202 const label = try br.takeSentinel(0);
203 const off = try br.takeLeb128(usize);
245204 const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label });
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;
205 const seek = br.seek;
206 br.seek = off;
207 try self.parseTrieNode(br, allocator, arena, prefix_label);
208 br.seek = seek;
250209 }
251210}
252211
......@@ -257,8 +216,8 @@ fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void {
257216 var arena = std.heap.ArenaAllocator.init(gpa);
258217 defer arena.deinit();
259218
260 var it: TrieIterator = .{ .data = data };
261 try self.parseTrieNode(&it, gpa, arena.allocator(), "");
219 var r: std.io.Reader = .fixed(data);
220 try self.parseTrieNode(&r, gpa, arena.allocator(), "");
262221}
263222
264223fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
......@@ -267,7 +226,7 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
267226
268227 const gpa = macho_file.base.comp.gpa;
269228
270 log.debug("parsing dylib from stub: {}", .{self.path});
229 log.debug("parsing dylib from stub: {f}", .{self.path});
271230
272231 const file = macho_file.getFileHandle(self.file_handle);
273232 var lib_stub = LibStub.loadFromFile(gpa, file) catch |err| {
......@@ -691,52 +650,32 @@ pub fn setSymbolExtra(self: *Dylib, index: u32, extra: Symbol.Extra) void {
691650 }
692651}
693652
694pub fn format(
695 self: *Dylib,
696 comptime unused_fmt_string: []const u8,
697 options: std.fmt.FormatOptions,
698 writer: anytype,
699) !void {
700 _ = self;
701 _ = unused_fmt_string;
702 _ = options;
703 _ = writer;
704 @compileError("do not format dylib directly");
705}
706
707pub fn fmtSymtab(self: *Dylib, macho_file: *MachO) std.fmt.Formatter(formatSymtab) {
653pub fn fmtSymtab(self: *Dylib, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
708654 return .{ .data = .{
709655 .dylib = self,
710656 .macho_file = macho_file,
711657 } };
712658}
713659
714const FormatContext = struct {
660const Format = struct {
715661 dylib: *Dylib,
716662 macho_file: *MachO,
717};
718663
719fn formatSymtab(
720 ctx: FormatContext,
721 comptime unused_fmt_string: []const u8,
722 options: std.fmt.FormatOptions,
723 writer: anytype,
724) !void {
725 _ = unused_fmt_string;
726 _ = options;
727 const dylib = ctx.dylib;
728 const macho_file = ctx.macho_file;
729 try writer.writeAll(" globals\n");
730 for (dylib.symbols.items, 0..) |sym, i| {
731 const ref = dylib.getSymbolRef(@intCast(i), macho_file);
732 if (ref.getFile(macho_file) == null) {
733 // TODO any better way of handling this?
734 try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
735 } else {
736 try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
664 fn symtab(f: Format, w: *Writer) Writer.Error!void {
665 const dylib = f.dylib;
666 const macho_file = f.macho_file;
667 try w.writeAll(" globals\n");
668 for (dylib.symbols.items, 0..) |sym, i| {
669 const ref = dylib.getSymbolRef(@intCast(i), macho_file);
670 if (ref.getFile(macho_file) == null) {
671 // TODO any better way of handling this?
672 try w.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
673 } else {
674 try w.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
675 }
737676 }
738677 }
739}
678};
740679
741680pub const TargetMatcher = struct {
742681 allocator: Allocator,
......@@ -948,19 +887,17 @@ const Export = struct {
948887 };
949888};
950889
890const std = @import("std");
951891const assert = std.debug.assert;
952const fat = @import("fat.zig");
953892const fs = std.fs;
954893const fmt = std.fmt;
955894const log = std.log.scoped(.link);
956895const macho = std.macho;
957896const math = std.math;
958897const mem = std.mem;
959const tapi = @import("../tapi.zig");
960const trace = @import("../../tracy.zig").trace;
961const std = @import("std");
962898const Allocator = mem.Allocator;
963899const Path = std.Build.Cache.Path;
900const Writer = std.io.Writer;
964901
965902const Dylib = @This();
966903const File = @import("file.zig").File;
......@@ -969,3 +906,6 @@ const LoadCommandIterator = macho.LoadCommandIterator;
969906const MachO = @import("../MachO.zig");
970907const Symbol = @import("Symbol.zig");
971908const Tbd = tapi.Tbd;
909const fat = @import("fat.zig");
910const tapi = @import("../tapi.zig");
911const trace = @import("../../tracy.zig").trace;
src/link/MachO/InternalObject.zig+28-41
......@@ -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.writer(gpa).print("{s}\x00", .{methname}) catch unreachable;
264 self.objc_methnames.print(gpa, "{s}\x00", .{methname}) catch unreachable;
265265
266266 const name_str = try self.addString(gpa, "ltmp");
267267 const sym_index = try self.addSymbol(gpa);
......@@ -836,62 +836,48 @@ fn needsObjcMsgsendSymbol(self: InternalObject) bool {
836836 return false;
837837}
838838
839const FormatContext = struct {
839const Format = struct {
840840 self: *InternalObject,
841841 macho_file: *MachO,
842
843 fn atoms(f: Format, w: *Writer) Writer.Error!void {
844 try w.writeAll(" atoms\n");
845 for (f.self.getAtoms()) |atom_index| {
846 const atom = f.self.getAtom(atom_index) orelse continue;
847 try w.print(" {f}\n", .{atom.fmt(f.macho_file)});
848 }
849 }
850
851 fn symtab(f: Format, w: *Writer) Writer.Error!void {
852 const macho_file = f.macho_file;
853 const self = f.self;
854 try w.writeAll(" symbols\n");
855 for (self.symbols.items, 0..) |sym, i| {
856 const ref = self.getSymbolRef(@intCast(i), macho_file);
857 if (ref.getFile(macho_file) == null) {
858 // TODO any better way of handling this?
859 try w.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
860 } else {
861 try w.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
862 }
863 }
864 }
842865};
843866
844pub fn fmtAtoms(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(formatAtoms) {
867pub fn fmtAtoms(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(Format, Format.atoms) {
845868 return .{ .data = .{
846869 .self = self,
847870 .macho_file = macho_file,
848871 } };
849872}
850873
851fn formatAtoms(
852 ctx: FormatContext,
853 comptime unused_fmt_string: []const u8,
854 options: std.fmt.FormatOptions,
855 writer: anytype,
856) !void {
857 _ = unused_fmt_string;
858 _ = options;
859 try writer.writeAll(" atoms\n");
860 for (ctx.self.getAtoms()) |atom_index| {
861 const atom = ctx.self.getAtom(atom_index) orelse continue;
862 try writer.print(" {}\n", .{atom.fmt(ctx.macho_file)});
863 }
864}
865
866pub fn fmtSymtab(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(formatSymtab) {
874pub fn fmtSymtab(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
867875 return .{ .data = .{
868876 .self = self,
869877 .macho_file = macho_file,
870878 } };
871879}
872880
873fn formatSymtab(
874 ctx: FormatContext,
875 comptime unused_fmt_string: []const u8,
876 options: std.fmt.FormatOptions,
877 writer: anytype,
878) !void {
879 _ = unused_fmt_string;
880 _ = options;
881 const macho_file = ctx.macho_file;
882 const self = ctx.self;
883 try writer.writeAll(" symbols\n");
884 for (self.symbols.items, 0..) |sym, i| {
885 const ref = self.getSymbolRef(@intCast(i), macho_file);
886 if (ref.getFile(macho_file) == null) {
887 // TODO any better way of handling this?
888 try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
889 } else {
890 try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
891 }
892 }
893}
894
895881const Section = struct {
896882 header: macho.section_64,
897883 relocs: std.ArrayListUnmanaged(Relocation) = .empty,
......@@ -908,6 +894,7 @@ const macho = std.macho;
908894const mem = std.mem;
909895const std = @import("std");
910896const trace = @import("../../tracy.zig").trace;
897const Writer = std.io.Writer;
911898
912899const Allocator = std.mem.Allocator;
913900const Atom = @import("Atom.zig");
src/link/MachO/Object.zig+101-164
......@@ -72,7 +72,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
7272 const tracy = trace(@src());
7373 defer tracy.end();
7474
75 log.debug("parsing {}", .{self.fmtPath()});
75 log.debug("parsing {f}", .{self.fmtPath()});
7676
7777 const gpa = macho_file.base.comp.gpa;
7878 const handle = macho_file.getFileHandle(self.file_handle);
......@@ -239,7 +239,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
239239
240240 if (self.platform) |platform| {
241241 if (!macho_file.platform.eqlTarget(platform)) {
242 try macho_file.reportParseError2(self.index, "invalid platform: {}", .{
242 try macho_file.reportParseError2(self.index, "invalid platform: {f}", .{
243243 platform.fmtTarget(cpu_arch),
244244 });
245245 return error.InvalidTarget;
......@@ -247,7 +247,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
247247 // TODO: this causes the CI to fail so I'm commenting this check out so that
248248 // I can work out the rest of the changes first
249249 // if (macho_file.platform.version.order(platform.version) == .lt) {
250 // try macho_file.reportParseError2(self.index, "object file built for newer platform: {}: {} < {}", .{
250 // try macho_file.reportParseError2(self.index, "object file built for newer platform: {f}: {f} < {f}", .{
251251 // macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),
252252 // macho_file.platform.version,
253253 // platform.version,
......@@ -308,7 +308,9 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {
308308 } else nlists.len;
309309
310310 if (nlist_start == nlist_end or nlists[nlist_start].nlist.n_value > sect.addr) {
311 const name = try std.fmt.allocPrintSentinel(allocator, "{s}${s}$begin", .{ sect.segName(), sect.sectName() }, 0);
311 const name = try std.fmt.allocPrintSentinel(allocator, "{s}${s}$begin", .{
312 sect.segName(), sect.sectName(),
313 }, 0);
312314 defer allocator.free(name);
313315 const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr;
314316 const atom_index = try self.addAtom(allocator, .{
......@@ -364,7 +366,9 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {
364366 // which cannot be contained in any non-zero atom (since then this atom
365367 // would exceed section boundaries). In order to facilitate this behaviour,
366368 // we create a dummy zero-sized atom at section end (addr + size).
367 const name = try std.fmt.allocPrintSentinel(allocator, "{s}${s}$end", .{ sect.segName(), sect.sectName() }, 0);
369 const name = try std.fmt.allocPrintSentinel(allocator, "{s}${s}$end", .{
370 sect.segName(), sect.sectName(),
371 }, 0);
368372 defer allocator.free(name);
369373 const atom_index = try self.addAtom(allocator, .{
370374 .name = try self.addString(allocator, name),
......@@ -1065,7 +1069,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi
10651069 }
10661070 }
10671071
1068 var it = eh_frame.Iterator{ .data = self.eh_frame_data.items };
1072 var it: eh_frame.Iterator = .{ .br = .fixed(self.eh_frame_data.items) };
10691073 while (try it.next()) |rec| {
10701074 switch (rec.tag) {
10711075 .cie => try self.cies.append(allocator, .{
......@@ -1694,11 +1698,11 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
16941698 };
16951699}
16961700
1697pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
1701pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) !void {
16981702 // Header
16991703 const size = try macho_file.cast(usize, self.output_ar_state.size);
17001704 const basename = std.fs.path.basename(self.path.sub_path);
1701 try Archive.writeHeader(basename, size, ar_format, writer);
1705 try Archive.writeHeader(bw, basename, size, ar_format);
17021706 // Data
17031707 const file = macho_file.getFileHandle(self.file_handle);
17041708 // TODO try using copyRangeAll
......@@ -1707,7 +1711,7 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ
17071711 defer gpa.free(data);
17081712 const amt = try file.preadAll(data, self.offset);
17091713 if (amt != size) return error.InputOutput;
1710 try writer.writeAll(data);
1714 try bw.writeAll(data);
17111715}
17121716
17131717pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
......@@ -1861,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
18611865 }
18621866 gpa.free(sections_data);
18631867 }
1864 @memset(sections_data, &[0]u8{});
1868 @memset(sections_data, &.{});
18651869 const file = macho_file.getFileHandle(self.file_handle);
18661870
18671871 for (headers, 0..) |header, n_sect| {
......@@ -2512,165 +2516,114 @@ pub fn readSectionData(self: Object, allocator: Allocator, file: File.Handle, n_
25122516 return data;
25132517}
25142518
2515pub fn format(
2516 self: *Object,
2517 comptime unused_fmt_string: []const u8,
2518 options: std.fmt.FormatOptions,
2519 writer: anytype,
2520) !void {
2521 _ = self;
2522 _ = unused_fmt_string;
2523 _ = options;
2524 _ = writer;
2525 @compileError("do not format objects directly");
2526}
2527
2528const FormatContext = struct {
2519const Format = struct {
25292520 object: *Object,
25302521 macho_file: *MachO,
2522
2523 fn atoms(f: Format, w: *Writer) Writer.Error!void {
2524 const object = f.object;
2525 const macho_file = f.macho_file;
2526 try w.writeAll(" atoms\n");
2527 for (object.getAtoms()) |atom_index| {
2528 const atom = object.getAtom(atom_index) orelse continue;
2529 try w.print(" {f}\n", .{atom.fmt(macho_file)});
2530 }
2531 }
2532 fn cies(f: Format, w: *Writer) Writer.Error!void {
2533 const object = f.object;
2534 try w.writeAll(" cies\n");
2535 for (object.cies.items, 0..) |cie, i| {
2536 try w.print(" cie({d}) : {f}\n", .{ i, cie.fmt(f.macho_file) });
2537 }
2538 }
2539 fn fdes(f: Format, w: *Writer) Writer.Error!void {
2540 const object = f.object;
2541 try w.writeAll(" fdes\n");
2542 for (object.fdes.items, 0..) |fde, i| {
2543 try w.print(" fde({d}) : {f}\n", .{ i, fde.fmt(f.macho_file) });
2544 }
2545 }
2546 fn unwindRecords(f: Format, w: *Writer) Writer.Error!void {
2547 const object = f.object;
2548 const macho_file = f.macho_file;
2549 try w.writeAll(" unwind records\n");
2550 for (object.unwind_records_indexes.items) |rec| {
2551 try w.print(" rec({d}) : {f}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) });
2552 }
2553 }
2554
2555 fn formatSymtab(f: Format, w: *Writer) Writer.Error!void {
2556 const object = f.object;
2557 const macho_file = f.macho_file;
2558 try w.writeAll(" symbols\n");
2559 for (object.symbols.items, 0..) |sym, i| {
2560 const ref = object.getSymbolRef(@intCast(i), macho_file);
2561 if (ref.getFile(macho_file) == null) {
2562 // TODO any better way of handling this?
2563 try w.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
2564 } else {
2565 try w.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
2566 }
2567 }
2568 for (object.stab_files.items) |sf| {
2569 try w.print(" stabs({s},{s},{s})\n", .{
2570 sf.getCompDir(object.*),
2571 sf.getTuName(object.*),
2572 sf.getOsoPath(object.*),
2573 });
2574 for (sf.stabs.items) |stab| {
2575 try w.print(" {f}", .{stab.fmt(object.*)});
2576 }
2577 }
2578 }
25312579};
25322580
2533pub fn fmtAtoms(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatAtoms) {
2581pub fn fmtAtoms(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.atoms) {
25342582 return .{ .data = .{
25352583 .object = self,
25362584 .macho_file = macho_file,
25372585 } };
25382586}
25392587
2540fn formatAtoms(
2541 ctx: FormatContext,
2542 comptime unused_fmt_string: []const u8,
2543 options: std.fmt.FormatOptions,
2544 writer: anytype,
2545) !void {
2546 _ = unused_fmt_string;
2547 _ = options;
2548 const object = ctx.object;
2549 const macho_file = ctx.macho_file;
2550 try writer.writeAll(" atoms\n");
2551 for (object.getAtoms()) |atom_index| {
2552 const atom = object.getAtom(atom_index) orelse continue;
2553 try writer.print(" {}\n", .{atom.fmt(macho_file)});
2554 }
2555}
2556
2557pub fn fmtCies(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatCies) {
2588pub fn fmtCies(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.cies) {
25582589 return .{ .data = .{
25592590 .object = self,
25602591 .macho_file = macho_file,
25612592 } };
25622593}
25632594
2564fn formatCies(
2565 ctx: FormatContext,
2566 comptime unused_fmt_string: []const u8,
2567 options: std.fmt.FormatOptions,
2568 writer: anytype,
2569) !void {
2570 _ = unused_fmt_string;
2571 _ = options;
2572 const object = ctx.object;
2573 try writer.writeAll(" cies\n");
2574 for (object.cies.items, 0..) |cie, i| {
2575 try writer.print(" cie({d}) : {}\n", .{ i, cie.fmt(ctx.macho_file) });
2576 }
2577}
2578
2579pub fn fmtFdes(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatFdes) {
2595pub fn fmtFdes(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.fdes) {
25802596 return .{ .data = .{
25812597 .object = self,
25822598 .macho_file = macho_file,
25832599 } };
25842600}
25852601
2586fn formatFdes(
2587 ctx: FormatContext,
2588 comptime unused_fmt_string: []const u8,
2589 options: std.fmt.FormatOptions,
2590 writer: anytype,
2591) !void {
2592 _ = unused_fmt_string;
2593 _ = options;
2594 const object = ctx.object;
2595 try writer.writeAll(" fdes\n");
2596 for (object.fdes.items, 0..) |fde, i| {
2597 try writer.print(" fde({d}) : {}\n", .{ i, fde.fmt(ctx.macho_file) });
2598 }
2599}
2600
2601pub fn fmtUnwindRecords(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatUnwindRecords) {
2602pub fn fmtUnwindRecords(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.unwindRecords) {
26022603 return .{ .data = .{
26032604 .object = self,
26042605 .macho_file = macho_file,
26052606 } };
26062607}
26072608
2608fn formatUnwindRecords(
2609 ctx: FormatContext,
2610 comptime unused_fmt_string: []const u8,
2611 options: std.fmt.FormatOptions,
2612 writer: anytype,
2613) !void {
2614 _ = unused_fmt_string;
2615 _ = options;
2616 const object = ctx.object;
2617 const macho_file = ctx.macho_file;
2618 try writer.writeAll(" unwind records\n");
2619 for (object.unwind_records_indexes.items) |rec| {
2620 try writer.print(" rec({d}) : {}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) });
2621 }
2622}
2623
2624pub fn fmtSymtab(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatSymtab) {
2609pub fn fmtSymtab(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
26252610 return .{ .data = .{
26262611 .object = self,
26272612 .macho_file = macho_file,
26282613 } };
26292614}
26302615
2631fn formatSymtab(
2632 ctx: FormatContext,
2633 comptime unused_fmt_string: []const u8,
2634 options: std.fmt.FormatOptions,
2635 writer: anytype,
2636) !void {
2637 _ = unused_fmt_string;
2638 _ = options;
2639 const object = ctx.object;
2640 const macho_file = ctx.macho_file;
2641 try writer.writeAll(" symbols\n");
2642 for (object.symbols.items, 0..) |sym, i| {
2643 const ref = object.getSymbolRef(@intCast(i), macho_file);
2644 if (ref.getFile(macho_file) == null) {
2645 // TODO any better way of handling this?
2646 try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
2647 } else {
2648 try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
2649 }
2650 }
2651 for (object.stab_files.items) |sf| {
2652 try writer.print(" stabs({s},{s},{s})\n", .{
2653 sf.getCompDir(object.*),
2654 sf.getTuName(object.*),
2655 sf.getOsoPath(object.*),
2656 });
2657 for (sf.stabs.items) |stab| {
2658 try writer.print(" {}", .{stab.fmt(object.*)});
2659 }
2660 }
2661}
2662
26632616pub fn fmtPath(self: Object) std.fmt.Formatter(Object, formatPath) {
26642617 return .{ .data = self };
26652618}
26662619
2667fn formatPath(object: Object, writer: *std.io.Writer) std.io.Writer.Error!void {
2620fn formatPath(object: Object, w: *Writer) Writer.Error!void {
26682621 if (object.in_archive) |ar| {
2669 try writer.print("{f}({s})", .{
2670 @as(Path, ar.path), object.path.basename(),
2622 try w.print("{f}({s})", .{
2623 ar.path, object.path.basename(),
26712624 });
26722625 } else {
2673 try writer.print("{f}", .{@as(Path, object.path)});
2626 try w.print("{f}", .{object.path});
26742627 }
26752628}
26762629
......@@ -2724,43 +2677,26 @@ const StabFile = struct {
27242677 return object.symbols.items[index];
27252678 }
27262679
2727 pub fn format(
2680 const Format = struct {
27282681 stab: Stab,
2729 comptime unused_fmt_string: []const u8,
2730 options: std.fmt.FormatOptions,
2731 writer: anytype,
2732 ) !void {
2733 _ = stab;
2734 _ = unused_fmt_string;
2735 _ = options;
2736 _ = writer;
2737 @compileError("do not format stabs directly");
2738 }
2682 object: Object,
27392683
2740 const StabFormatContext = struct { Stab, Object };
2684 fn default(f: Stab.Format, w: *Writer) Writer.Error!void {
2685 const stab = f.stab;
2686 const sym = stab.getSymbol(f.object).?;
2687 if (stab.is_func) {
2688 try w.print("func({d})", .{stab.index.?});
2689 } else if (sym.visibility == .global) {
2690 try w.print("gsym({d})", .{stab.index.?});
2691 } else {
2692 try w.print("stsym({d})", .{stab.index.?});
2693 }
2694 }
2695 };
27412696
2742 pub fn fmt(stab: Stab, object: Object) std.fmt.Formatter(format2) {
2697 pub fn fmt(stab: Stab, object: Object) std.fmt.Formatter(Stab.Format, Stab.Format.default) {
27432698 return .{ .data = .{ stab, object } };
27442699 }
2745
2746 fn format2(
2747 ctx: StabFormatContext,
2748 comptime unused_fmt_string: []const u8,
2749 options: std.fmt.FormatOptions,
2750 writer: anytype,
2751 ) !void {
2752 _ = unused_fmt_string;
2753 _ = options;
2754 const stab, const object = ctx;
2755 const sym = stab.getSymbol(object).?;
2756 if (stab.is_func) {
2757 try writer.print("func({d})", .{stab.index.?});
2758 } else if (sym.visibility == .global) {
2759 try writer.print("gsym({d})", .{stab.index.?});
2760 } else {
2761 try writer.print("stsym({d})", .{stab.index.?});
2762 }
2763 }
27642700 };
27652701};
27662702
......@@ -3150,17 +3086,18 @@ const aarch64 = struct {
31503086 }
31513087};
31523088
3089const std = @import("std");
31533090const assert = std.debug.assert;
3154const eh_frame = @import("eh_frame.zig");
31553091const log = std.log.scoped(.link);
31563092const macho = std.macho;
31573093const math = std.math;
31583094const mem = std.mem;
3159const trace = @import("../../tracy.zig").trace;
3160const std = @import("std");
31613095const Path = std.Build.Cache.Path;
3096const Allocator = std.mem.Allocator;
3097const Writer = std.io.Writer;
31623098
3163const Allocator = mem.Allocator;
3099const eh_frame = @import("eh_frame.zig");
3100const trace = @import("../../tracy.zig").trace;
31643101const Archive = @import("Archive.zig");
31653102const Atom = @import("Atom.zig");
31663103const Cie = eh_frame.Cie;
src/link/MachO/Relocation.zig+44-49
......@@ -70,57 +70,51 @@ pub fn lessThan(ctx: void, lhs: Relocation, rhs: Relocation) bool {
7070 return lhs.offset < rhs.offset;
7171}
7272
73const FormatCtx = struct { Relocation, std.Target.Cpu.Arch };
74
75pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(formatPretty) {
73pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(Format, Format.pretty) {
7674 return .{ .data = .{ rel, cpu_arch } };
7775}
7876
79fn formatPretty(
80 ctx: FormatCtx,
81 comptime unused_fmt_string: []const u8,
82 options: std.fmt.FormatOptions,
83 writer: anytype,
84) !void {
85 _ = options;
86 _ = unused_fmt_string;
87 const rel, const cpu_arch = ctx;
88 const str = switch (rel.type) {
89 .signed => "X86_64_RELOC_SIGNED",
90 .signed1 => "X86_64_RELOC_SIGNED_1",
91 .signed2 => "X86_64_RELOC_SIGNED_2",
92 .signed4 => "X86_64_RELOC_SIGNED_4",
93 .got_load => "X86_64_RELOC_GOT_LOAD",
94 .tlv => "X86_64_RELOC_TLV",
95 .page => "ARM64_RELOC_PAGE21",
96 .pageoff => "ARM64_RELOC_PAGEOFF12",
97 .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21",
98 .got_load_pageoff => "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
99 .tlvp_page => "ARM64_RELOC_TLVP_LOAD_PAGE21",
100 .tlvp_pageoff => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
101 .branch => switch (cpu_arch) {
102 .x86_64 => "X86_64_RELOC_BRANCH",
103 .aarch64 => "ARM64_RELOC_BRANCH26",
104 else => unreachable,
105 },
106 .got => switch (cpu_arch) {
107 .x86_64 => "X86_64_RELOC_GOT",
108 .aarch64 => "ARM64_RELOC_POINTER_TO_GOT",
109 else => unreachable,
110 },
111 .subtractor => switch (cpu_arch) {
112 .x86_64 => "X86_64_RELOC_SUBTRACTOR",
113 .aarch64 => "ARM64_RELOC_SUBTRACTOR",
114 else => unreachable,
115 },
116 .unsigned => switch (cpu_arch) {
117 .x86_64 => "X86_64_RELOC_UNSIGNED",
118 .aarch64 => "ARM64_RELOC_UNSIGNED",
119 else => unreachable,
120 },
121 };
122 try writer.writeAll(str);
123}
77const Format = struct {
78 relocation: Relocation,
79 arch: std.Target.Cpu.Arch,
80
81 fn pretty(f: Format, w: *Writer) Writer.Error!void {
82 try w.writeAll(switch (f.relocation.type) {
83 .signed => "X86_64_RELOC_SIGNED",
84 .signed1 => "X86_64_RELOC_SIGNED_1",
85 .signed2 => "X86_64_RELOC_SIGNED_2",
86 .signed4 => "X86_64_RELOC_SIGNED_4",
87 .got_load => "X86_64_RELOC_GOT_LOAD",
88 .tlv => "X86_64_RELOC_TLV",
89 .page => "ARM64_RELOC_PAGE21",
90 .pageoff => "ARM64_RELOC_PAGEOFF12",
91 .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21",
92 .got_load_pageoff => "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
93 .tlvp_page => "ARM64_RELOC_TLVP_LOAD_PAGE21",
94 .tlvp_pageoff => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
95 .branch => switch (f.arch) {
96 .x86_64 => "X86_64_RELOC_BRANCH",
97 .aarch64 => "ARM64_RELOC_BRANCH26",
98 else => unreachable,
99 },
100 .got => switch (f.arch) {
101 .x86_64 => "X86_64_RELOC_GOT",
102 .aarch64 => "ARM64_RELOC_POINTER_TO_GOT",
103 else => unreachable,
104 },
105 .subtractor => switch (f.arch) {
106 .x86_64 => "X86_64_RELOC_SUBTRACTOR",
107 .aarch64 => "ARM64_RELOC_SUBTRACTOR",
108 else => unreachable,
109 },
110 .unsigned => switch (f.arch) {
111 .x86_64 => "X86_64_RELOC_UNSIGNED",
112 .aarch64 => "ARM64_RELOC_UNSIGNED",
113 else => unreachable,
114 },
115 });
116 }
117};
124118
125119pub const Type = enum {
126120 // x86_64
......@@ -164,10 +158,11 @@ pub const Type = enum {
164158
165159const Tag = enum { local, @"extern" };
166160
161const std = @import("std");
167162const assert = std.debug.assert;
168163const macho = std.macho;
169164const math = std.math;
170const std = @import("std");
165const Writer = std.io.Writer;
171166
172167const Atom = @import("Atom.zig");
173168const MachO = @import("../MachO.zig");
src/link/MachO/Symbol.zig+40-59
......@@ -286,71 +286,51 @@ pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) vo
286286 }
287287}
288288
289pub fn format(
290 symbol: Symbol,
291 comptime unused_fmt_string: []const u8,
292 options: std.fmt.FormatOptions,
293 writer: anytype,
294) !void {
295 _ = symbol;
296 _ = unused_fmt_string;
297 _ = options;
298 _ = writer;
299 @compileError("do not format symbols directly");
300}
301
302const FormatContext = struct {
303 symbol: Symbol,
304 macho_file: *MachO,
305};
306
307pub fn fmt(symbol: Symbol, macho_file: *MachO) std.fmt.Formatter(format2) {
289pub fn fmt(symbol: Symbol, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
308290 return .{ .data = .{
309291 .symbol = symbol,
310292 .macho_file = macho_file,
311293 } };
312294}
313295
314fn format2(
315 ctx: FormatContext,
316 comptime unused_fmt_string: []const u8,
317 options: std.fmt.FormatOptions,
318 writer: anytype,
319) !void {
320 _ = options;
321 _ = unused_fmt_string;
322 const symbol = ctx.symbol;
323 try writer.print("%{d} : {s} : @{x}", .{
324 symbol.nlist_idx,
325 symbol.getName(ctx.macho_file),
326 symbol.getAddress(.{}, ctx.macho_file),
327 });
328 if (symbol.getFile(ctx.macho_file)) |file| {
329 if (symbol.getOutputSectionIndex(ctx.macho_file) != 0) {
330 try writer.print(" : sect({d})", .{symbol.getOutputSectionIndex(ctx.macho_file)});
331 }
332 if (symbol.getAtom(ctx.macho_file)) |atom| {
333 try writer.print(" : atom({d})", .{atom.atom_index});
334 }
335 var buf: [3]u8 = .{'_'} ** 3;
336 if (symbol.flags.@"export") buf[0] = 'E';
337 if (symbol.flags.import) buf[1] = 'I';
338 switch (symbol.visibility) {
339 .local => buf[2] = 'L',
340 .hidden => buf[2] = 'H',
341 .global => buf[2] = 'G',
342 }
343 try writer.print(" : {s}", .{&buf});
344 if (symbol.flags.weak) try writer.writeAll(" : weak");
345 if (symbol.isSymbolStab(ctx.macho_file)) try writer.writeAll(" : stab");
346 switch (file) {
347 .zig_object => |x| try writer.print(" : zig_object({d})", .{x.index}),
348 .internal => |x| try writer.print(" : internal({d})", .{x.index}),
349 .object => |x| try writer.print(" : object({d})", .{x.index}),
350 .dylib => |x| try writer.print(" : dylib({d})", .{x.index}),
351 }
352 } else try writer.writeAll(" : unresolved");
353}
296const Format = struct {
297 symbol: Symbol,
298 macho_file: *MachO,
299
300 fn format2(f: Format, w: *Writer) Writer.Error!void {
301 const symbol = f.symbol;
302 try w.print("%{d} : {s} : @{x}", .{
303 symbol.nlist_idx,
304 symbol.getName(f.macho_file),
305 symbol.getAddress(.{}, f.macho_file),
306 });
307 if (symbol.getFile(f.macho_file)) |file| {
308 if (symbol.getOutputSectionIndex(f.macho_file) != 0) {
309 try w.print(" : sect({d})", .{symbol.getOutputSectionIndex(f.macho_file)});
310 }
311 if (symbol.getAtom(f.macho_file)) |atom| {
312 try w.print(" : atom({d})", .{atom.atom_index});
313 }
314 var buf: [3]u8 = .{'_'} ** 3;
315 if (symbol.flags.@"export") buf[0] = 'E';
316 if (symbol.flags.import) buf[1] = 'I';
317 switch (symbol.visibility) {
318 .local => buf[2] = 'L',
319 .hidden => buf[2] = 'H',
320 .global => buf[2] = 'G',
321 }
322 try w.print(" : {s}", .{&buf});
323 if (symbol.flags.weak) try w.writeAll(" : weak");
324 if (symbol.isSymbolStab(f.macho_file)) try w.writeAll(" : stab");
325 switch (file) {
326 .zig_object => |x| try w.print(" : zig_object({d})", .{x.index}),
327 .internal => |x| try w.print(" : internal({d})", .{x.index}),
328 .object => |x| try w.print(" : object({d})", .{x.index}),
329 .dylib => |x| try w.print(" : dylib({d})", .{x.index}),
330 }
331 } else try w.writeAll(" : unresolved");
332 }
333};
354334
355335pub const Flags = packed struct {
356336 /// Whether the symbol is imported at runtime.
......@@ -437,6 +417,7 @@ pub const Index = u32;
437417const assert = std.debug.assert;
438418const macho = std.macho;
439419const std = @import("std");
420const Writer = std.io.Writer;
440421
441422const Atom = @import("Atom.zig");
442423const File = @import("file.zig").File;
src/link/MachO/Thunk.zig+16-35
......@@ -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, writer: anytype) !void {
23pub fn write(thunk: Thunk, macho_file: *MachO, bw: *Writer) !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 writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
29 try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
3030 const off: u12 = @truncate(taddr);
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);
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);
3333 }
3434}
3535
......@@ -61,47 +61,27 @@ pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void {
6161 }
6262}
6363
64pub fn format(
65 thunk: Thunk,
66 comptime unused_fmt_string: []const u8,
67 options: std.fmt.FormatOptions,
68 writer: anytype,
69) !void {
70 _ = thunk;
71 _ = unused_fmt_string;
72 _ = options;
73 _ = writer;
74 @compileError("do not format Thunk directly");
75}
76
77pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Formatter(format2) {
64pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
7865 return .{ .data = .{
7966 .thunk = thunk,
8067 .macho_file = macho_file,
8168 } };
8269}
8370
84const FormatContext = struct {
71const Format = struct {
8572 thunk: Thunk,
8673 macho_file: *MachO,
87};
8874
89fn format2(
90 ctx: FormatContext,
91 comptime unused_fmt_string: []const u8,
92 options: std.fmt.FormatOptions,
93 writer: anytype,
94) !void {
95 _ = options;
96 _ = unused_fmt_string;
97 const thunk = ctx.thunk;
98 const macho_file = ctx.macho_file;
99 try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
100 for (thunk.symbols.keys()) |ref| {
101 const sym = ref.getSymbol(macho_file).?;
102 try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
75 fn default(f: Format, w: *Writer) Writer.Error!void {
76 const thunk = f.thunk;
77 const macho_file = f.macho_file;
78 try w.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
79 for (thunk.symbols.keys()) |ref| {
80 const sym = ref.getSymbol(macho_file).?;
81 try w.print(" {f} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
82 }
10383 }
104}
84};
10585
10686const trampoline_size = 3 * @sizeOf(u32);
10787
......@@ -115,6 +95,7 @@ const math = std.math;
11595const mem = std.mem;
11696const std = @import("std");
11797const trace = @import("../../tracy.zig").trace;
98const Writer = std.io.Writer;
11899
119100const Allocator = mem.Allocator;
120101const Atom = @import("Atom.zig");
src/link/MachO/UnwindInfo.zig+46-97
......@@ -133,7 +133,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
133133 for (info.records.items) |ref| {
134134 const rec = ref.getUnwindRecord(macho_file);
135135 const atom = rec.getAtom(macho_file);
136 log.debug("@{x}-{x} : {s} : rec({d}) : object({d}) : {}", .{
136 log.debug("@{x}-{x} : {s} : rec({d}) : object({d}) : {f}", .{
137137 rec.getAtomAddress(macho_file),
138138 rec.getAtomAddress(macho_file) + rec.length,
139139 atom.getName(macho_file),
......@@ -202,7 +202,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
202202 if (i >= max_common_encodings) break;
203203 if (slice[i].count < 2) continue;
204204 info.appendCommonEncoding(slice[i].enc);
205 log.debug("adding common encoding: {d} => {}", .{ i, slice[i].enc });
205 log.debug("adding common encoding: {d} => {f}", .{ i, slice[i].enc });
206206 }
207207 }
208208
......@@ -255,7 +255,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
255255 page.kind = .compressed;
256256 }
257257
258 log.debug("{}", .{page.fmt(info.*)});
258 log.debug("{f}", .{page.fmt(info.*)});
259259
260260 try info.pages.append(gpa, page);
261261 }
......@@ -289,13 +289,10 @@ pub fn calcSize(info: UnwindInfo) usize {
289289 return total_size;
290290}
291291
292pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
292pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!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
299296 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);
300297 const common_encodings_count: u32 = info.common_encodings_count;
301298 const personalities_offset: u32 = common_encodings_offset + common_encodings_count * @sizeOf(u32);
......@@ -303,7 +300,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
303300 const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);
304301 const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));
305302
306 try writer.writeStruct(macho.unwind_info_section_header{
303 try bw.writeStruct(macho.unwind_info_section_header{
307304 .commonEncodingsArraySectionOffset = common_encodings_offset,
308305 .commonEncodingsArrayCount = common_encodings_count,
309306 .personalityArraySectionOffset = personalities_offset,
......@@ -312,11 +309,11 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
312309 .indexCount = indexes_count,
313310 });
314311
315 try writer.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));
312 try bw.writeAll(mem.sliceAsBytes(info.common_encodings[0..info.common_encodings_count]));
316313
317314 for (info.personalities[0..info.personalities_count]) |ref| {
318315 const sym = ref.getSymbol(macho_file).?;
319 try writer.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little);
316 try bw.writeInt(u32, @intCast(sym.getGotAddress(macho_file) - seg.vmaddr), .little);
320317 }
321318
322319 const pages_base_offset = @as(u32, @intCast(header.size - (info.pages.items.len * second_level_page_bytes)));
......@@ -325,7 +322,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
325322 for (info.pages.items, 0..) |page, i| {
326323 assert(page.count > 0);
327324 const rec = info.records.items[page.start].getUnwindRecord(macho_file);
328 try writer.writeStruct(macho.unwind_info_section_header_index_entry{
325 try bw.writeStruct(macho.unwind_info_section_header_index_entry{
329326 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
330327 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
331328 .lsdaIndexArraySectionOffset = lsda_base_offset +
......@@ -335,7 +332,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
335332
336333 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);
337334 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));
338 try writer.writeStruct(macho.unwind_info_section_header_index_entry{
335 try bw.writeStruct(macho.unwind_info_section_header_index_entry{
339336 .functionOffset = sentinel_address,
340337 .secondLevelPagesSectionOffset = 0,
341338 .lsdaIndexArraySectionOffset = lsda_base_offset +
......@@ -344,23 +341,20 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
344341
345342 for (info.lsdas.items) |index| {
346343 const rec = info.records.items[index].getUnwindRecord(macho_file);
347 try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{
344 try bw.writeStruct(macho.unwind_info_section_header_lsda_index_entry{
348345 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
349346 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),
350347 });
351348 }
352349
353350 for (info.pages.items) |page| {
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 }
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);
361355 }
362356
363 @memset(buffer[stream.pos..], 0);
357 @memset(bw.unusedCapacitySlice(), 0);
364358}
365359
366360fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {
......@@ -455,15 +449,9 @@ pub const Encoding = extern struct {
455449 return enc.enc == other.enc;
456450 }
457451
458 pub fn format(
459 enc: Encoding,
460 comptime unused_fmt_string: []const u8,
461 options: std.fmt.FormatOptions,
462 writer: anytype,
463 ) !void {
464 _ = unused_fmt_string;
465 _ = options;
466 try writer.print("0x{x:0>8}", .{enc.enc});
452 pub fn format(enc: Encoding, w: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void {
453 comptime assert(unused_fmt_string.len == 0);
454 try w.print("0x{x:0>8}", .{enc.enc});
467455 }
468456};
469457
......@@ -517,48 +505,28 @@ pub const Record = struct {
517505 return lsda.getAddress(macho_file) + rec.lsda_offset;
518506 }
519507
520 pub fn format(
521 rec: Record,
522 comptime unused_fmt_string: []const u8,
523 options: std.fmt.FormatOptions,
524 writer: anytype,
525 ) !void {
526 _ = rec;
527 _ = unused_fmt_string;
528 _ = options;
529 _ = writer;
530 @compileError("do not format UnwindInfo.Records directly");
531 }
532
533 pub fn fmt(rec: Record, macho_file: *MachO) std.fmt.Formatter(format2) {
508 pub fn fmt(rec: Record, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
534509 return .{ .data = .{
535510 .rec = rec,
536511 .macho_file = macho_file,
537512 } };
538513 }
539514
540 const FormatContext = struct {
515 const Format = struct {
541516 rec: Record,
542517 macho_file: *MachO,
543 };
544518
545 fn format2(
546 ctx: FormatContext,
547 comptime unused_fmt_string: []const u8,
548 options: std.fmt.FormatOptions,
549 writer: anytype,
550 ) !void {
551 _ = unused_fmt_string;
552 _ = options;
553 const rec = ctx.rec;
554 const macho_file = ctx.macho_file;
555 try writer.print("{x} : len({x})", .{
556 rec.enc.enc, rec.length,
557 });
558 if (rec.enc.isDwarf(macho_file)) try writer.print(" : fde({d})", .{rec.fde});
559 try writer.print(" : {s}", .{rec.getAtom(macho_file).getName(macho_file)});
560 if (!rec.alive) try writer.writeAll(" : [*]");
561 }
519 fn default(f: Format, w: *Writer) Writer.Error!void {
520 const rec = f.rec;
521 const macho_file = f.macho_file;
522 try w.print("{x} : len({x})", .{
523 rec.enc.enc, rec.length,
524 });
525 if (rec.enc.isDwarf(macho_file)) try w.print(" : fde({d})", .{rec.fde});
526 try w.print(" : {s}", .{rec.getAtom(macho_file).getName(macho_file)});
527 if (!rec.alive) try w.writeAll(" : [*]");
528 }
529 };
562530
563531 pub const Index = u32;
564532
......@@ -613,45 +581,25 @@ const Page = struct {
613581 return null;
614582 }
615583
616 fn format(
617 page: *const Page,
618 comptime unused_format_string: []const u8,
619 options: std.fmt.FormatOptions,
620 writer: anytype,
621 ) !void {
622 _ = page;
623 _ = unused_format_string;
624 _ = options;
625 _ = writer;
626 @compileError("do not format Page directly; use page.fmt()");
627 }
628
629 const FormatPageContext = struct {
584 const Format = struct {
630585 page: Page,
631586 info: UnwindInfo,
632 };
633587
634 fn format2(
635 ctx: FormatPageContext,
636 comptime unused_format_string: []const u8,
637 options: std.fmt.FormatOptions,
638 writer: anytype,
639 ) @TypeOf(writer).Error!void {
640 _ = options;
641 _ = unused_format_string;
642 try writer.writeAll("Page:\n");
643 try writer.print(" kind: {s}\n", .{@tagName(ctx.page.kind)});
644 try writer.print(" entries: {d} - {d}\n", .{
645 ctx.page.start,
646 ctx.page.start + ctx.page.count,
647 });
648 try writer.print(" encodings (count = {d})\n", .{ctx.page.page_encodings_count});
649 for (ctx.page.page_encodings[0..ctx.page.page_encodings_count], 0..) |enc, i| {
650 try writer.print(" {d}: {}\n", .{ ctx.info.common_encodings_count + i, enc });
588 fn default(f: Format, w: *Writer) Writer.Error!void {
589 try w.writeAll("Page:\n");
590 try w.print(" kind: {s}\n", .{@tagName(f.page.kind)});
591 try w.print(" entries: {d} - {d}\n", .{
592 f.page.start,
593 f.page.start + f.page.count,
594 });
595 try w.print(" encodings (count = {d})\n", .{f.page.page_encodings_count});
596 for (f.page.page_encodings[0..f.page.page_encodings_count], 0..) |enc, i| {
597 try w.print(" {d}: {f}\n", .{ f.info.common_encodings_count + i, enc });
598 }
651599 }
652 }
600 };
653601
654 fn fmt(page: Page, info: UnwindInfo) std.fmt.Formatter(format2) {
602 fn fmt(page: Page, info: UnwindInfo) std.fmt.Formatter(Format, Format.default) {
655603 return .{ .data = .{
656604 .page = page,
657605 .info = info,
......@@ -720,6 +668,7 @@ const macho = std.macho;
720668const math = std.math;
721669const mem = std.mem;
722670const trace = @import("../../tracy.zig").trace;
671const Writer = std.io.Writer;
723672
724673const Allocator = mem.Allocator;
725674const Atom = @import("Atom.zig");
src/link/MachO/ZigObject.zig+36-51
......@@ -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, ar_format: Archive.Format, writer: anytype) !void {
320pub fn writeAr(self: ZigObject, bw: *Writer, ar_format: Archive.Format) Writer.Error!void {
321321 // Header
322322 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
323 try Archive.writeHeader(self.basename, size, ar_format, writer);
323 try Archive.writeHeader(bw, self.basename, size, ar_format);
324324 // Data
325 try writer.writeAll(self.data.items);
325 try bw.writeAll(self.data.items);
326326}
327327
328328pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void {
......@@ -618,7 +618,7 @@ pub fn getNavVAddr(
618618 const zcu = pt.zcu;
619619 const ip = &zcu.intern_pool;
620620 const nav = ip.getNav(nav_index);
621 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
621 log.debug("getNavVAddr {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
622622 const sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(
623623 macho_file,
624624 nav.name.toSlice(ip),
......@@ -884,7 +884,6 @@ 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,
888887 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
889888 };
890889 }
......@@ -921,7 +920,6 @@ pub fn updateNav(
921920
922921 if (debug_wip_nav) |*wip_nav| self.dwarf.?.finishWipNav(pt, nav_index, wip_nav) catch |err| switch (err) {
923922 error.OutOfMemory => return error.OutOfMemory,
924 error.Overflow => return error.Overflow,
925923 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
926924 };
927925 } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index);
......@@ -943,7 +941,7 @@ fn updateNavCode(
943941 const ip = &zcu.intern_pool;
944942 const nav = ip.getNav(nav_index);
945943
946 log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
944 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
947945
948946 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
949947 const required_alignment = switch (pt.navAlignment(nav_index)) {
......@@ -981,7 +979,7 @@ fn updateNavCode(
981979 if (need_realloc) {
982980 atom.grow(macho_file) catch |err|
983981 return macho_file.base.cgFail(nav_index, "failed to grow atom: {s}", .{@errorName(err)});
984 log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value });
982 log.debug("growing {f} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom.value });
985983 if (old_vaddr != atom.value) {
986984 sym.value = 0;
987985 nlist.n_value = 0;
......@@ -1023,7 +1021,7 @@ fn updateTlv(
10231021 const ip = &pt.zcu.intern_pool;
10241022 const nav = ip.getNav(nav_index);
10251023
1026 log.debug("updateTlv {} (0x{x})", .{ nav.fqn.fmt(ip), nav_index });
1024 log.debug("updateTlv {f} (0x{x})", .{ nav.fqn.fmt(ip), nav_index });
10271025
10281026 // 1. Lower TLV initializer
10291027 const init_sym_index = try self.createTlvInitializer(
......@@ -1351,7 +1349,7 @@ fn updateLazySymbol(
13511349 defer code_buffer.deinit(gpa);
13521350
13531351 const name_str = blk: {
1354 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
1352 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{
13551353 @tagName(lazy_sym.kind),
13561354 Type.fromInterned(lazy_sym.ty).fmt(pt),
13571355 });
......@@ -1430,7 +1428,7 @@ pub fn deleteExport(
14301428 } orelse return;
14311429 const nlist_index = metadata.@"export"(self, name.toSlice(&zcu.intern_pool)) orelse return;
14321430
1433 log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)});
1431 log.debug("deleting export '{f}'", .{name.fmt(&zcu.intern_pool)});
14341432
14351433 const nlist = &self.symtab.items(.nlist)[nlist_index.*];
14361434 self.symtab.items(.size)[nlist_index.*] = 0;
......@@ -1678,64 +1676,50 @@ pub fn asFile(self: *ZigObject) File {
16781676 return .{ .zig_object = self };
16791677}
16801678
1681pub fn fmtSymtab(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatSymtab) {
1679pub fn fmtSymtab(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
16821680 return .{ .data = .{
16831681 .self = self,
16841682 .macho_file = macho_file,
16851683 } };
16861684}
16871685
1688const FormatContext = struct {
1686const Format = struct {
16891687 self: *ZigObject,
16901688 macho_file: *MachO,
1691};
16921689
1693fn formatSymtab(
1694 ctx: FormatContext,
1695 comptime unused_fmt_string: []const u8,
1696 options: std.fmt.FormatOptions,
1697 writer: anytype,
1698) !void {
1699 _ = unused_fmt_string;
1700 _ = options;
1701 try writer.writeAll(" symbols\n");
1702 const self = ctx.self;
1703 const macho_file = ctx.macho_file;
1704 for (self.symbols.items, 0..) |sym, i| {
1705 const ref = self.getSymbolRef(@intCast(i), macho_file);
1706 if (ref.getFile(macho_file) == null) {
1707 // TODO any better way of handling this?
1708 try writer.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
1709 } else {
1710 try writer.print(" {}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
1690 fn symtab(f: Format, w: *Writer) Writer.Error!void {
1691 try w.writeAll(" symbols\n");
1692 const self = f.self;
1693 const macho_file = f.macho_file;
1694 for (self.symbols.items, 0..) |sym, i| {
1695 const ref = self.getSymbolRef(@intCast(i), macho_file);
1696 if (ref.getFile(macho_file) == null) {
1697 // TODO any better way of handling this?
1698 try w.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
1699 } else {
1700 try w.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
1701 }
17111702 }
17121703 }
1713}
17141704
1715pub fn fmtAtoms(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatAtoms) {
1705 fn atoms(f: Format, w: *Writer) Writer.Error!void {
1706 const self = f.self;
1707 const macho_file = f.macho_file;
1708 try w.writeAll(" atoms\n");
1709 for (self.getAtoms()) |atom_index| {
1710 const atom = self.getAtom(atom_index) orelse continue;
1711 try w.print(" {f}\n", .{atom.fmt(macho_file)});
1712 }
1713 }
1714};
1715
1716pub fn fmtAtoms(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(Format, Format.atoms) {
17161717 return .{ .data = .{
17171718 .self = self,
17181719 .macho_file = macho_file,
17191720 } };
17201721}
17211722
1722fn formatAtoms(
1723 ctx: FormatContext,
1724 comptime unused_fmt_string: []const u8,
1725 options: std.fmt.FormatOptions,
1726 writer: anytype,
1727) !void {
1728 _ = unused_fmt_string;
1729 _ = options;
1730 const self = ctx.self;
1731 const macho_file = ctx.macho_file;
1732 try writer.writeAll(" atoms\n");
1733 for (self.getAtoms()) |atom_index| {
1734 const atom = self.getAtom(atom_index) orelse continue;
1735 try writer.print(" {}\n", .{atom.fmt(macho_file)});
1736 }
1737}
1738
17391723const AvMetadata = struct {
17401724 symbol_index: Symbol.Index,
17411725 /// A list of all exports aliases of this Av.
......@@ -1797,6 +1781,7 @@ const mem = std.mem;
17971781const target_util = @import("../../target.zig");
17981782const trace = @import("../../tracy.zig").trace;
17991783const std = @import("std");
1784const Writer = std.io.Writer;
18001785
18011786const Allocator = std.mem.Allocator;
18021787const Archive = @import("Archive.zig");
src/link/MachO/dead_strip.zig+4-9
......@@ -117,7 +117,7 @@ fn mark(roots: []*Atom, objects: []const File.Index, macho_file: *MachO) void {
117117fn markLive(atom: *Atom, macho_file: *MachO) void {
118118 assert(atom.visited.load(.seq_cst));
119119 atom.setAlive(true);
120 track_live_log.debug("{}marking live atom({d},{s})", .{
120 track_live_log.debug("{f}marking live atom({d},{s})", .{
121121 track_live_level,
122122 atom.atom_index,
123123 atom.getName(macho_file),
......@@ -196,15 +196,9 @@ const Level = struct {
196196 self.value += 1;
197197 }
198198
199 pub fn format(
200 self: *const @This(),
201 comptime unused_fmt_string: []const u8,
202 options: std.fmt.FormatOptions,
203 writer: anytype,
204 ) !void {
199 pub fn format(self: *const @This(), bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void {
205200 _ = unused_fmt_string;
206 _ = options;
207 try writer.writeByteNTimes(' ', self.value);
201 try bw.splatByteAll(' ', self.value);
208202 }
209203};
210204
......@@ -219,6 +213,7 @@ const mem = std.mem;
219213const trace = @import("../../tracy.zig").trace;
220214const track_live_log = std.log.scoped(.dead_strip_track_live);
221215const std = @import("std");
216const Writer = std.io.Writer;
222217
223218const Allocator = mem.Allocator;
224219const Atom = @import("Atom.zig");
src/link/MachO/dyld_info/Rebase.zig+48-47
......@@ -3,7 +3,7 @@ buffer: std.ArrayListUnmanaged(u8) = .empty,
33
44pub const Entry = struct {
55 offset: u64,
6 segment_id: u8,
6 segment_id: u4,
77
88 pub fn lessThan(ctx: void, entry: Entry, other: Entry) bool {
99 _ = ctx;
......@@ -110,33 +110,35 @@ 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 const writer = rebase.buffer.writer(gpa);
113 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &rebase.buffer);
114 const bw = &aw.writer;
115 defer rebase.buffer = aw.toArrayList();
114116
115117 log.debug("rebase opcodes", .{});
116118
117119 std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);
118120
119 try setTypePointer(writer);
121 try setTypePointer(bw);
120122
121123 var start: usize = 0;
122124 var seg_id: ?u8 = null;
123125 for (rebase.entries.items, 0..) |entry, i| {
124126 if (seg_id != null and seg_id.? == entry.segment_id) continue;
125 try finalizeSegment(rebase.entries.items[start..i], writer);
127 try finalizeSegment(rebase.entries.items[start..i], bw);
126128 seg_id = entry.segment_id;
127129 start = i;
128130 }
129131
130 try finalizeSegment(rebase.entries.items[start..], writer);
131 try done(writer);
132 try finalizeSegment(rebase.entries.items[start..], bw);
133 try done(bw);
132134}
133135
134fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
136fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
135137 if (entries.len == 0) return;
136138
137139 const segment_id = entries[0].segment_id;
138140 var offset = entries[0].offset;
139 try setSegmentOffset(segment_id, offset, writer);
141 try setSegmentOffset(segment_id, offset, bw);
140142
141143 var count: usize = 0;
142144 var skip: u64 = 0;
......@@ -155,7 +157,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
155157 .start => {
156158 if (offset < current_offset) {
157159 const delta = current_offset - offset;
158 try addAddr(delta, writer);
160 try addAddr(delta, bw);
159161 offset += delta;
160162 }
161163 state = .times;
......@@ -175,7 +177,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
175177 offset += skip;
176178 i -= 1;
177179 } else {
178 try rebaseTimes(count, writer);
180 try rebaseTimes(count, bw);
179181 state = .start;
180182 i -= 1;
181183 }
......@@ -184,9 +186,9 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
184186 if (current_offset < offset) {
185187 count -= 1;
186188 if (count == 1) {
187 try rebaseAddAddr(skip, writer);
189 try rebaseAddAddr(skip, bw);
188190 } else {
189 try rebaseTimesSkip(count, skip, writer);
191 try rebaseTimesSkip(count, skip, bw);
190192 }
191193 state = .start;
192194 offset = offset - (@sizeOf(u64) + skip);
......@@ -199,7 +201,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
199201 count += 1;
200202 offset += @sizeOf(u64) + skip;
201203 } else {
202 try rebaseTimesSkip(count, skip, writer);
204 try rebaseTimesSkip(count, skip, bw);
203205 state = .start;
204206 i -= 1;
205207 }
......@@ -210,68 +212,66 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
210212 switch (state) {
211213 .start => unreachable,
212214 .times => {
213 try rebaseTimes(count, writer);
215 try rebaseTimes(count, bw);
214216 },
215217 .times_skip => {
216 try rebaseTimesSkip(count, skip, writer);
218 try rebaseTimesSkip(count, skip, bw);
217219 },
218220 }
219221}
220222
221fn setTypePointer(writer: anytype) !void {
223fn setTypePointer(bw: *Writer) Writer.Error!void {
222224 log.debug(">>> set type: {d}", .{macho.REBASE_TYPE_POINTER});
223 try writer.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.REBASE_TYPE_POINTER)));
225 try bw.writeByte(macho.REBASE_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.REBASE_TYPE_POINTER)));
224226}
225227
226fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
228fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {
227229 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, 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);
230 try bw.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
231 try bw.writeLeb128(offset);
230232}
231233
232fn rebaseAddAddr(addr: u64, writer: anytype) !void {
234fn rebaseAddAddr(addr: u64, bw: *Writer) Writer.Error!void {
233235 log.debug(">>> rebase with add: {x}", .{addr});
234 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
235 try std.leb.writeUleb128(writer, addr);
236 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
237 try bw.writeLeb128(addr);
236238}
237239
238fn rebaseTimes(count: usize, writer: anytype) !void {
240fn rebaseTimes(count: usize, bw: *Writer) Writer.Error!void {
239241 log.debug(">>> rebase with count: {d}", .{count});
240242 if (count <= 0xf) {
241 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count)));
243 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_IMM_TIMES | @as(u4, @truncate(count)));
242244 } else {
243 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
244 try std.leb.writeUleb128(writer, count);
245 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
246 try bw.writeLeb128(count);
245247 }
246248}
247249
248fn rebaseTimesSkip(count: usize, skip: u64, writer: anytype) !void {
250fn rebaseTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {
249251 log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, 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);
252 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
253 try bw.writeLeb128(count);
254 try bw.writeLeb128(skip);
253255}
254256
255fn addAddr(addr: u64, writer: anytype) !void {
257fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {
256258 log.debug(">>> add: {x}", .{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);
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);
266266}
267267
268fn done(writer: anytype) !void {
268fn done(bw: *Writer) Writer.Error!void {
269269 log.debug(">>> done", .{});
270 try writer.writeByte(macho.REBASE_OPCODE_DONE);
270 try bw.writeByte(macho.REBASE_OPCODE_DONE);
271271}
272272
273pub fn write(rebase: Rebase, writer: anytype) !void {
274 try writer.writeAll(rebase.buffer.items);
273pub fn write(rebase: Rebase, bw: *Writer) Writer.Error!void {
274 try bw.writeAll(rebase.buffer.items);
275275}
276276
277277test "rebase - no entries" {
......@@ -654,9 +654,10 @@ const log = std.log.scoped(.link_dyld_info);
654654const macho = std.macho;
655655const mem = std.mem;
656656const testing = std.testing;
657const trace = @import("../../../tracy.zig").trace;
658
659657const Allocator = mem.Allocator;
658const Writer = std.io.Writer;
659
660const trace = @import("../../../tracy.zig").trace;
660661const File = @import("../file.zig").File;
661662const MachO = @import("../../MachO.zig");
662663const Rebase = @This();
src/link/MachO/dyld_info/Trie.zig+32-37
......@@ -31,7 +31,7 @@
3131
3232/// The root node of the trie.
3333root: ?Node.Index = null,
34buffer: std.ArrayListUnmanaged(u8) = .empty,
34buffer: []u8 = &.{},
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.items.len), @alignOf(u64));
126 macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.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 = std.fifo.LinearFifo(Node.Index, .Dynamic).init(allocator);
141 var fifo = DeprecatedLinearFifo(Node.Index).init(allocator);
142142 defer fifo.deinit();
143143
144144 try fifo.writeItem(self.root.?);
......@@ -164,9 +164,11 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
164164 }
165165 }
166166
167 try self.buffer.ensureTotalCapacityPrecise(allocator, size);
167 assert(self.buffer.len == 0);
168 self.buffer = try allocator.alloc(u8, size);
169 var bw: Writer = .fixed(self.buffer);
168170 for (ordered_nodes.items) |node_index| {
169 try self.writeNode(node_index, self.buffer.writer(allocator));
171 try self.writeNode(node_index, &bw);
170172 }
171173}
172174
......@@ -181,17 +183,17 @@ const FinalizeNodeResult = struct {
181183
182184/// Updates offset of this node in the output byte stream.
183185fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult {
184 var stream = std.io.countingWriter(std.io.null_writer);
185 const writer = stream.writer();
186 var buf: [1024]u8 = undefined;
187 var bw: Writer = .discarding(&buf);
186188 const slice = self.nodes.slice();
187189
188190 var node_size: u32 = 0;
189191 if (slice.items(.is_terminal)[node_index]) {
190192 const export_flags = slice.items(.export_flags)[node_index];
191193 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
192 try leb.writeULEB128(writer, export_flags);
193 try leb.writeULEB128(writer, vmaddr_offset);
194 try leb.writeULEB128(writer, stream.bytes_written);
194 try bw.writeLeb128(export_flags);
195 try bw.writeLeb128(vmaddr_offset);
196 try bw.writeLeb128(bw.count);
195197 } else {
196198 node_size += 1; // 0x0 for non-terminal nodes
197199 }
......@@ -201,13 +203,13 @@ fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !Final
201203 const edge = &self.edges.items[edge_index];
202204 const next_node_offset = slice.items(.trie_offset)[edge.node];
203205 node_size += @intCast(edge.label.len + 1);
204 try leb.writeULEB128(writer, next_node_offset);
206 try bw.writeLeb128(next_node_offset);
205207 }
206208
207209 const trie_offset = slice.items(.trie_offset)[node_index];
208210 const updated = offset_in_trie != trie_offset;
209211 slice.items(.trie_offset)[node_index] = offset_in_trie;
210 node_size += @intCast(stream.bytes_written);
212 node_size += @intCast(bw.count);
211213
212214 return .{ .node_size = node_size, .updated = updated };
213215}
......@@ -223,12 +225,11 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {
223225 }
224226 self.nodes.deinit(allocator);
225227 self.edges.deinit(allocator);
226 self.buffer.deinit(allocator);
228 allocator.free(self.buffer);
227229}
228230
229pub fn write(self: Trie, writer: anytype) !void {
230 if (self.buffer.items.len == 0) return;
231 try writer.writeAll(self.buffer.items);
231pub fn write(self: Trie, bw: *Writer) Writer.Error!void {
232 try bw.writeAll(self.buffer);
232233}
233234
234235/// Writes this node to a byte stream.
......@@ -237,7 +238,7 @@ pub fn write(self: Trie, writer: anytype) !void {
237238/// iterate over `Trie.ordered_nodes` and call this method on each node.
238239/// This is one of the requirements of the MachO.
239240/// Panics if `finalize` was not called before calling this method.
240fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
241fn writeNode(self: *Trie, node_index: Node.Index, bw: *Writer) !void {
241242 const slice = self.nodes.slice();
242243 const edges = slice.items(.edges)[node_index];
243244 const is_terminal = slice.items(.is_terminal)[node_index];
......@@ -245,36 +246,28 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
245246 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
246247
247248 if (is_terminal) {
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);
249 const start = bw.count;
251250 // TODO Implement for special flags.
252251 assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
253252 export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
254 try leb.writeULEB128(info_stream.writer(), export_flags);
255 try leb.writeULEB128(info_stream.writer(), vmaddr_offset);
256
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);
257256 // Encode the size of the terminal node info.
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]);
257 try bw.writeLeb128(bw.count - start);
265258 } else {
266259 // Non-terminal node is delimited by 0 byte.
267 try writer.writeByte(0);
260 try bw.writeByte(0);
268261 }
269 // Write number of edges (max legal number of edges is 256).
270 try writer.writeByte(@as(u8, @intCast(edges.items.len)));
262 // Write number of edges (max legal number of edges is 255).
263 try bw.writeByte(@intCast(edges.items.len));
271264
272265 for (edges.items) |edge_index| {
273266 const edge = self.edges.items[edge_index];
274267 // Write edge label and offset to next node in trie.
275 try writer.writeAll(edge.label);
276 try writer.writeByte(0);
277 try leb.writeULEB128(writer, slice.items(.trie_offset)[edge.node]);
268 try bw.writeAll(edge.label);
269 try bw.writeByte(0);
270 try bw.writeLeb128(slice.items(.trie_offset)[edge.node]);
278271 }
279272}
280273
......@@ -414,8 +407,10 @@ const macho = std.macho;
414407const mem = std.mem;
415408const std = @import("std");
416409const testing = std.testing;
417const trace = @import("../../../tracy.zig").trace;
410const Writer = std.io.Writer;
418411
412const trace = @import("../../../tracy.zig").trace;
413const DeprecatedLinearFifo = @import("../../../deprecated.zig").LinearFifo;
419414const Allocator = mem.Allocator;
420415const MachO = @import("../../MachO.zig");
421416const Trie = @This();
src/link/MachO/dyld_info/bind.zig+155-187
......@@ -1,7 +1,7 @@
11pub const Entry = struct {
22 target: MachO.Ref,
33 offset: u64,
4 segment_id: u8,
4 segment_id: u4,
55 addend: i64,
66
77 pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool {
......@@ -20,14 +20,12 @@ pub const Bind = struct {
2020 entries: std.ArrayListUnmanaged(Entry) = .empty,
2121 buffer: std.ArrayListUnmanaged(u8) = .empty,
2222
23 const Self = @This();
24
25 pub fn deinit(self: *Self, gpa: Allocator) void {
26 self.entries.deinit(gpa);
27 self.buffer.deinit(gpa);
23 pub fn deinit(bind: *Bind, gpa: Allocator) void {
24 bind.entries.deinit(gpa);
25 bind.buffer.deinit(gpa);
2826 }
2927
30 pub fn updateSize(self: *Self, macho_file: *MachO) !void {
28 pub fn updateSize(bind: *Bind, macho_file: *MachO) !void {
3129 const tracy = trace(@src());
3230 defer tracy.end();
3331
......@@ -56,15 +54,12 @@ pub const Bind = struct {
5654 const addend = rel.addend + rel.getRelocAddend(cpu_arch);
5755 const sym = rel.getTargetSymbol(atom.*, macho_file);
5856 if (sym.isTlvInit(macho_file)) continue;
59 const entry = Entry{
57 if (sym.flags.import or (!(sym.flags.@"export" and sym.flags.weak) and sym.flags.interposable)) (try bind.entries.addOne(gpa)).* = .{
6058 .target = rel.getTargetSymbolRef(atom.*, macho_file),
6159 .offset = atom_addr + rel_offset - seg.vmaddr,
6260 .segment_id = seg_id,
6361 .addend = addend,
6462 };
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 }
6863 }
6964 }
7065 }
......@@ -75,15 +70,12 @@ pub const Bind = struct {
7570 for (macho_file.got.symbols.items, 0..) |ref, idx| {
7671 const sym = ref.getSymbol(macho_file).?;
7772 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
78 const entry = Entry{
73 if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{
7974 .target = ref,
8075 .offset = addr - seg.vmaddr,
8176 .segment_id = seg_id,
8277 .addend = 0,
8378 };
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 }
8779 }
8880 }
8981
......@@ -94,15 +86,12 @@ pub const Bind = struct {
9486 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
9587 const sym = ref.getSymbol(macho_file).?;
9688 const addr = sect.addr + idx * @sizeOf(u64);
97 const bind_entry = Entry{
89 if (sym.flags.import and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
9890 .target = ref,
9991 .offset = addr - seg.vmaddr,
10092 .segment_id = seg_id,
10193 .addend = 0,
10294 };
103 if (sym.flags.import and sym.flags.weak) {
104 try self.entries.append(gpa, bind_entry);
105 }
10695 }
10796 }
10897
......@@ -113,49 +102,48 @@ pub const Bind = struct {
113102 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
114103 const sym = ref.getSymbol(macho_file).?;
115104 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);
116 const entry = Entry{
105 if (sym.flags.import or (sym.flags.@"export" and sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{
117106 .target = ref,
118107 .offset = addr - seg.vmaddr,
119108 .segment_id = seg_id,
120109 .addend = 0,
121110 };
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 }
125111 }
126112 }
127113
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));
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));
130116 }
131117
132 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
133 if (self.entries.items.len == 0) return;
118 fn finalize(bind: *Bind, gpa: Allocator, ctx: *MachO) !void {
119 if (bind.entries.items.len == 0) return;
134120
135 const writer = self.buffer.writer(gpa);
121 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
122 const bw = &aw.writer;
123 defer bind.buffer = aw.toArrayList();
136124
137125 log.debug("bind opcodes", .{});
138126
139 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
127 std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan);
140128
141129 var start: usize = 0;
142130 var seg_id: ?u8 = null;
143 for (self.entries.items, 0..) |entry, i| {
131 for (bind.entries.items, 0..) |entry, i| {
144132 if (seg_id != null and seg_id.? == entry.segment_id) continue;
145 try finalizeSegment(self.entries.items[start..i], ctx, writer);
133 try finalizeSegment(bind.entries.items[start..i], ctx, bw);
146134 seg_id = entry.segment_id;
147135 start = i;
148136 }
149137
150 try finalizeSegment(self.entries.items[start..], ctx, writer);
151 try done(writer);
138 try finalizeSegment(bind.entries.items[start..], ctx, bw);
139 try done(bw);
152140 }
153141
154 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {
142 fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void {
155143 if (entries.len == 0) return;
156144
157145 const seg_id = entries[0].segment_id;
158 try setSegmentOffset(seg_id, 0, writer);
146 try setSegmentOffset(seg_id, 0, bw);
159147
160148 var offset: u64 = 0;
161149 var addend: i64 = 0;
......@@ -175,15 +163,15 @@ pub const Bind = struct {
175163 if (target == null or !target.?.eql(current.target)) {
176164 switch (state) {
177165 .start => {},
178 .bind_single => try doBind(writer),
179 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
166 .bind_single => try doBind(bw),
167 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
180168 }
181169 state = .start;
182170 target = current.target;
183171
184172 const sym = current.target.getSymbol(ctx).?;
185173 const name = sym.getName(ctx);
186 const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
174 const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
187175 const ordinal: i16 = ord: {
188176 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
189177 if (sym.flags.import) {
......@@ -195,13 +183,13 @@ pub const Bind = struct {
195183 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
196184 };
197185
198 try setSymbol(name, flags, writer);
199 try setTypePointer(writer);
200 try setDylibOrdinal(ordinal, writer);
186 try setSymbol(name, flags, bw);
187 try setTypePointer(bw);
188 try setDylibOrdinal(ordinal, bw);
201189
202190 if (current.addend != addend) {
203191 addend = current.addend;
204 try setAddend(addend, writer);
192 try setAddend(addend, bw);
205193 }
206194 }
207195
......@@ -210,11 +198,11 @@ pub const Bind = struct {
210198 switch (state) {
211199 .start => {
212200 if (current.offset < offset) {
213 try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), writer);
201 try addAddr(@bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset))), bw);
214202 offset = offset - (offset - current.offset);
215203 } else if (current.offset > offset) {
216204 const delta = current.offset - offset;
217 try addAddr(delta, writer);
205 try addAddr(delta, bw);
218206 offset += delta;
219207 }
220208 state = .bind_single;
......@@ -223,7 +211,7 @@ pub const Bind = struct {
223211 },
224212 .bind_single => {
225213 if (current.offset == offset) {
226 try doBind(writer);
214 try doBind(bw);
227215 state = .start;
228216 } else if (current.offset > offset) {
229217 const delta = current.offset - offset;
......@@ -237,9 +225,9 @@ pub const Bind = struct {
237225 if (current.offset < offset) {
238226 count -= 1;
239227 if (count == 1) {
240 try doBindAddAddr(skip, writer);
228 try doBindAddAddr(skip, bw);
241229 } else {
242 try doBindTimesSkip(count, skip, writer);
230 try doBindTimesSkip(count, skip, bw);
243231 }
244232 state = .start;
245233 offset = offset - (@sizeOf(u64) + skip);
......@@ -248,7 +236,7 @@ pub const Bind = struct {
248236 count += 1;
249237 offset += @sizeOf(u64) + skip;
250238 } else {
251 try doBindTimesSkip(count, skip, writer);
239 try doBindTimesSkip(count, skip, bw);
252240 state = .start;
253241 i -= 1;
254242 }
......@@ -258,13 +246,13 @@ pub const Bind = struct {
258246
259247 switch (state) {
260248 .start => unreachable,
261 .bind_single => try doBind(writer),
262 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
249 .bind_single => try doBind(bw),
250 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
263251 }
264252 }
265253
266 pub fn write(self: Self, writer: anytype) !void {
267 try writer.writeAll(self.buffer.items);
254 pub fn write(bind: Bind, bw: *Writer) Writer.Error!void {
255 try bw.writeAll(bind.buffer.items);
268256 }
269257};
270258
......@@ -272,14 +260,12 @@ pub const WeakBind = struct {
272260 entries: std.ArrayListUnmanaged(Entry) = .empty,
273261 buffer: std.ArrayListUnmanaged(u8) = .empty,
274262
275 const Self = @This();
276
277 pub fn deinit(self: *Self, gpa: Allocator) void {
278 self.entries.deinit(gpa);
279 self.buffer.deinit(gpa);
263 pub fn deinit(bind: *WeakBind, gpa: Allocator) void {
264 bind.entries.deinit(gpa);
265 bind.buffer.deinit(gpa);
280266 }
281267
282 pub fn updateSize(self: *Self, macho_file: *MachO) !void {
268 pub fn updateSize(bind: *WeakBind, macho_file: *MachO) !void {
283269 const tracy = trace(@src());
284270 defer tracy.end();
285271
......@@ -308,15 +294,12 @@ pub const WeakBind = struct {
308294 const addend = rel.addend + rel.getRelocAddend(cpu_arch);
309295 const sym = rel.getTargetSymbol(atom.*, macho_file);
310296 if (sym.isTlvInit(macho_file)) continue;
311 const entry = Entry{
297 if (!sym.isLocal() and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
312298 .target = rel.getTargetSymbolRef(atom.*, macho_file),
313299 .offset = atom_addr + rel_offset - seg.vmaddr,
314300 .segment_id = seg_id,
315301 .addend = addend,
316302 };
317 if (!sym.isLocal() and sym.flags.weak) {
318 try self.entries.append(gpa, entry);
319 }
320303 }
321304 }
322305 }
......@@ -327,15 +310,12 @@ pub const WeakBind = struct {
327310 for (macho_file.got.symbols.items, 0..) |ref, idx| {
328311 const sym = ref.getSymbol(macho_file).?;
329312 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
330 const entry = Entry{
313 if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
331314 .target = ref,
332315 .offset = addr - seg.vmaddr,
333316 .segment_id = seg_id,
334317 .addend = 0,
335318 };
336 if (sym.flags.weak) {
337 try self.entries.append(gpa, entry);
338 }
339319 }
340320 }
341321
......@@ -347,15 +327,12 @@ pub const WeakBind = struct {
347327 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
348328 const sym = ref.getSymbol(macho_file).?;
349329 const addr = sect.addr + idx * @sizeOf(u64);
350 const bind_entry = Entry{
330 if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
351331 .target = ref,
352332 .offset = addr - seg.vmaddr,
353333 .segment_id = seg_id,
354334 .addend = 0,
355335 };
356 if (sym.flags.weak) {
357 try self.entries.append(gpa, bind_entry);
358 }
359336 }
360337 }
361338
......@@ -366,49 +343,48 @@ pub const WeakBind = struct {
366343 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
367344 const sym = ref.getSymbol(macho_file).?;
368345 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);
369 const entry = Entry{
346 if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
370347 .target = ref,
371348 .offset = addr - seg.vmaddr,
372349 .segment_id = seg_id,
373350 .addend = 0,
374351 };
375 if (sym.flags.weak) {
376 try self.entries.append(gpa, entry);
377 }
378352 }
379353 }
380354
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));
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));
383357 }
384358
385 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
386 if (self.entries.items.len == 0) return;
359 fn finalize(bind: *WeakBind, gpa: Allocator, ctx: *MachO) !void {
360 if (bind.entries.items.len == 0) return;
387361
388 const writer = self.buffer.writer(gpa);
362 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
363 const bw = &aw.writer;
364 defer bind.buffer = aw.toArrayList();
389365
390366 log.debug("weak bind opcodes", .{});
391367
392 std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan);
368 std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan);
393369
394370 var start: usize = 0;
395371 var seg_id: ?u8 = null;
396 for (self.entries.items, 0..) |entry, i| {
372 for (bind.entries.items, 0..) |entry, i| {
397373 if (seg_id != null and seg_id.? == entry.segment_id) continue;
398 try finalizeSegment(self.entries.items[start..i], ctx, writer);
374 try finalizeSegment(bind.entries.items[start..i], ctx, bw);
399375 seg_id = entry.segment_id;
400376 start = i;
401377 }
402378
403 try finalizeSegment(self.entries.items[start..], ctx, writer);
404 try done(writer);
379 try finalizeSegment(bind.entries.items[start..], ctx, bw);
380 try done(bw);
405381 }
406382
407 fn finalizeSegment(entries: []const Entry, ctx: *MachO, writer: anytype) !void {
383 fn finalizeSegment(entries: []const Entry, ctx: *MachO, bw: *Writer) Writer.Error!void {
408384 if (entries.len == 0) return;
409385
410386 const seg_id = entries[0].segment_id;
411 try setSegmentOffset(seg_id, 0, writer);
387 try setSegmentOffset(seg_id, 0, bw);
412388
413389 var offset: u64 = 0;
414390 var addend: i64 = 0;
......@@ -428,8 +404,8 @@ pub const WeakBind = struct {
428404 if (target == null or !target.?.eql(current.target)) {
429405 switch (state) {
430406 .start => {},
431 .bind_single => try doBind(writer),
432 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
407 .bind_single => try doBind(bw),
408 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
433409 }
434410 state = .start;
435411 target = current.target;
......@@ -438,12 +414,12 @@ pub const WeakBind = struct {
438414 const name = sym.getName(ctx);
439415 const flags: u8 = 0; // TODO NON_WEAK_DEFINITION
440416
441 try setSymbol(name, flags, writer);
442 try setTypePointer(writer);
417 try setSymbol(name, flags, bw);
418 try setTypePointer(bw);
443419
444420 if (current.addend != addend) {
445421 addend = current.addend;
446 try setAddend(addend, writer);
422 try setAddend(addend, bw);
447423 }
448424 }
449425
......@@ -452,11 +428,11 @@ pub const WeakBind = struct {
452428 switch (state) {
453429 .start => {
454430 if (current.offset < offset) {
455 try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), writer);
431 try addAddr(@as(u64, @bitCast(@as(i64, @intCast(current.offset)) - @as(i64, @intCast(offset)))), bw);
456432 offset = offset - (offset - current.offset);
457433 } else if (current.offset > offset) {
458434 const delta = current.offset - offset;
459 try addAddr(delta, writer);
435 try addAddr(delta, bw);
460436 offset += delta;
461437 }
462438 state = .bind_single;
......@@ -465,7 +441,7 @@ pub const WeakBind = struct {
465441 },
466442 .bind_single => {
467443 if (current.offset == offset) {
468 try doBind(writer);
444 try doBind(bw);
469445 state = .start;
470446 } else if (current.offset > offset) {
471447 const delta = current.offset - offset;
......@@ -479,9 +455,9 @@ pub const WeakBind = struct {
479455 if (current.offset < offset) {
480456 count -= 1;
481457 if (count == 1) {
482 try doBindAddAddr(skip, writer);
458 try doBindAddAddr(skip, bw);
483459 } else {
484 try doBindTimesSkip(count, skip, writer);
460 try doBindTimesSkip(count, skip, bw);
485461 }
486462 state = .start;
487463 offset = offset - (@sizeOf(u64) + skip);
......@@ -490,7 +466,7 @@ pub const WeakBind = struct {
490466 count += 1;
491467 offset += @sizeOf(u64) + skip;
492468 } else {
493 try doBindTimesSkip(count, skip, writer);
469 try doBindTimesSkip(count, skip, bw);
494470 state = .start;
495471 i -= 1;
496472 }
......@@ -500,13 +476,13 @@ pub const WeakBind = struct {
500476
501477 switch (state) {
502478 .start => unreachable,
503 .bind_single => try doBind(writer),
504 .bind_times_skip => try doBindTimesSkip(count, skip, writer),
479 .bind_single => try doBind(bw),
480 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
505481 }
506482 }
507483
508 pub fn write(self: Self, writer: anytype) !void {
509 try writer.writeAll(self.buffer.items);
484 pub fn write(bind: WeakBind, bw: *Writer) Writer.Error!void {
485 try bw.writeAll(bind.buffer.items);
510486 }
511487};
512488
......@@ -515,15 +491,13 @@ pub const LazyBind = struct {
515491 buffer: std.ArrayListUnmanaged(u8) = .empty,
516492 offsets: std.ArrayListUnmanaged(u32) = .empty,
517493
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);
494 pub fn deinit(bind: *LazyBind, gpa: Allocator) void {
495 bind.entries.deinit(gpa);
496 bind.buffer.deinit(gpa);
497 bind.offsets.deinit(gpa);
524498 }
525499
526 pub fn updateSize(self: *Self, macho_file: *MachO) !void {
500 pub fn updateSize(bind: *LazyBind, macho_file: *MachO) !void {
527501 const tracy = trace(@src());
528502 defer tracy.end();
529503
......@@ -537,36 +511,35 @@ pub const LazyBind = struct {
537511 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
538512 const sym = ref.getSymbol(macho_file).?;
539513 const addr = sect.addr + idx * @sizeOf(u64);
540 const bind_entry = Entry{
514 if ((sym.flags.import and !sym.flags.weak) or (sym.flags.interposable and !sym.flags.weak)) (try bind.entries.addOne(gpa)).* = .{
541515 .target = ref,
542516 .offset = addr - seg.vmaddr,
543517 .segment_id = seg_id,
544518 .addend = 0,
545519 };
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 }
549520 }
550521
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));
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));
553524 }
554525
555 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {
556 try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);
526 fn finalize(bind: *LazyBind, gpa: Allocator, ctx: *MachO) !void {
527 try bind.offsets.ensureTotalCapacityPrecise(gpa, bind.entries.items.len);
557528
558 const writer = self.buffer.writer(gpa);
529 var aw: std.io.Writer.Allocating = .fromArrayList(gpa, &bind.buffer);
530 const bw = &aw.writer;
531 defer bind.buffer = aw.toArrayList();
559532
560533 log.debug("lazy bind opcodes", .{});
561534
562535 var addend: i64 = 0;
563536
564 for (self.entries.items) |entry| {
565 self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len));
537 for (bind.entries.items) |entry| {
538 bind.offsets.appendAssumeCapacity(@intCast(bind.buffer.items.len));
566539
567540 const sym = entry.target.getSymbol(ctx).?;
568541 const name = sym.getName(ctx);
569 const flags: u8 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
542 const flags: u4 = if (sym.weakRef(ctx)) macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT else 0;
570543 const ordinal: i16 = ord: {
571544 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
572545 if (sym.flags.import) {
......@@ -578,121 +551,116 @@ pub const LazyBind = struct {
578551 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
579552 };
580553
581 try setSegmentOffset(entry.segment_id, entry.offset, writer);
582 try setSymbol(name, flags, writer);
583 try setDylibOrdinal(ordinal, writer);
554 try setSegmentOffset(entry.segment_id, entry.offset, bw);
555 try setSymbol(name, flags, bw);
556 try setDylibOrdinal(ordinal, bw);
584557
585558 if (entry.addend != addend) {
586 try setAddend(entry.addend, writer);
559 try setAddend(entry.addend, bw);
587560 addend = entry.addend;
588561 }
589562
590 try doBind(writer);
591 try done(writer);
563 try doBind(bw);
564 try done(bw);
592565 }
593566 }
594567
595 pub fn write(self: Self, writer: anytype) !void {
596 try writer.writeAll(self.buffer.items);
568 pub fn write(bind: LazyBind, bw: *Writer) Writer.Error!void {
569 try bw.writeAll(bind.buffer.items);
597570 }
598571};
599572
600fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {
573fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {
601574 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });
602 try writer.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
603 try std.leb.writeUleb128(writer, offset);
575 try bw.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segment_id);
576 try bw.writeLeb128(offset);
604577}
605578
606fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void {
579fn setSymbol(name: []const u8, flags: u4, bw: *Writer) Writer.Error!void {
607580 log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });
608 try writer.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | @as(u4, @truncate(flags)));
609 try writer.writeAll(name);
610 try writer.writeByte(0);
581 try bw.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags);
582 try bw.writeAll(name);
583 try bw.writeByte(0);
611584}
612585
613fn setTypePointer(writer: anytype) !void {
586fn setTypePointer(bw: *Writer) Writer.Error!void {
614587 log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});
615 try writer.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @truncate(macho.BIND_TYPE_POINTER)));
588 try bw.writeByte(macho.BIND_OPCODE_SET_TYPE_IMM | @as(u4, @intCast(macho.BIND_TYPE_POINTER)));
616589}
617590
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 }
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 },
639610 }
640611}
641612
642fn setAddend(addend: i64, writer: anytype) !void {
613fn setAddend(addend: i64, bw: *Writer) Writer.Error!void {
643614 log.debug(">>> set addend: {x}", .{addend});
644 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
645 try std.leb.writeIleb128(writer, addend);
615 try bw.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
616 try bw.writeLeb128(addend);
646617}
647618
648fn doBind(writer: anytype) !void {
619fn doBind(bw: *Writer) Writer.Error!void {
649620 log.debug(">>> bind", .{});
650 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);
621 try bw.writeByte(macho.BIND_OPCODE_DO_BIND);
651622}
652623
653fn doBindAddAddr(addr: u64, writer: anytype) !void {
624fn doBindAddAddr(addr: u64, bw: *Writer) Writer.Error!void {
654625 log.debug(">>> bind with add: {x}", .{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);
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);
666633}
667634
668fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void {
635fn doBindTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {
669636 log.debug(">>> bind with count: {d} and skip: {x}", .{ count, 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);
637 try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
638 try bw.writeLeb128(count);
639 try bw.writeLeb128(skip);
673640}
674641
675fn addAddr(addr: u64, writer: anytype) !void {
642fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {
676643 log.debug(">>> add: {x}", .{addr});
677 try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
678 try std.leb.writeUleb128(writer, addr);
644 try bw.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
645 try bw.writeLeb128(addr);
679646}
680647
681fn done(writer: anytype) !void {
648fn done(bw: *Writer) Writer.Error!void {
682649 log.debug(">>> done", .{});
683 try writer.writeByte(macho.BIND_OPCODE_DONE);
650 try bw.writeByte(macho.BIND_OPCODE_DONE);
684651}
685652
653const std = @import("std");
686654const assert = std.debug.assert;
687655const leb = std.leb;
688656const log = std.log.scoped(.link_dyld_info);
689657const macho = std.macho;
690658const mem = std.mem;
691659const testing = std.testing;
692const trace = @import("../../../tracy.zig").trace;
693const std = @import("std");
660const Allocator = std.mem.Allocator;
661const Writer = std.io.Writer;
694662
695const Allocator = mem.Allocator;
663const trace = @import("../../../tracy.zig").trace;
696664const File = @import("../file.zig").File;
697665const MachO = @import("../../MachO.zig");
698666const Symbol = @import("../Symbol.zig");
src/link/MachO/eh_frame.zig+56-100
......@@ -12,36 +12,33 @@ pub const Cie = struct {
1212 const tracy = trace(@src());
1313 defer tracy.end();
1414
15 const data = cie.getData(macho_file);
16 const aug = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(data.ptr + 9)), 0);
15 var r: std.io.Reader = .fixed(cie.getData(macho_file));
1716
17 try r.discard(9);
18 const aug = try r.takeSentinel(0);
1819 if (aug[0] != 'z') return; // TODO should we error out?
1920
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
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
2825
2926 for (aug[1..]) |ch| switch (ch) {
3027 'R' => {
31 const enc = try reader.readByte();
28 const enc = try r.takeByte();
3229 if (enc != DW_EH_PE.pcrel | DW_EH_PE.absptr) {
3330 @panic("unexpected pointer encoding"); // TODO error
3431 }
3532 },
3633 'P' => {
37 const enc = try reader.readByte();
34 const enc = try r.takeByte();
3835 if (enc != DW_EH_PE.pcrel | DW_EH_PE.indirect | DW_EH_PE.sdata4) {
3936 @panic("unexpected personality pointer encoding"); // TODO error
4037 }
41 _ = try reader.readInt(u32, .little); // personality pointer
38 _ = try r.takeInt(u32, .little); // personality pointer
4239 },
4340 'L' => {
44 const enc = try reader.readByte();
41 const enc = try r.takeByte();
4542 switch (enc & DW_EH_PE.type_mask) {
4643 DW_EH_PE.sdata4 => cie.lsda_size = .p32,
4744 DW_EH_PE.absptr => cie.lsda_size = .p64,
......@@ -81,46 +78,26 @@ pub const Cie = struct {
8178 return true;
8279 }
8380
84 pub fn format(
85 cie: Cie,
86 comptime unused_fmt_string: []const u8,
87 options: std.fmt.FormatOptions,
88 writer: anytype,
89 ) !void {
90 _ = cie;
91 _ = unused_fmt_string;
92 _ = options;
93 _ = writer;
94 @compileError("do not format CIEs directly");
95 }
96
97 pub fn fmt(cie: Cie, macho_file: *MachO) std.fmt.Formatter(format2) {
81 pub fn fmt(cie: Cie, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
9882 return .{ .data = .{
9983 .cie = cie,
10084 .macho_file = macho_file,
10185 } };
10286 }
10387
104 const FormatContext = struct {
88 const Format = struct {
10589 cie: Cie,
10690 macho_file: *MachO,
107 };
10891
109 fn format2(
110 ctx: FormatContext,
111 comptime unused_fmt_string: []const u8,
112 options: std.fmt.FormatOptions,
113 writer: anytype,
114 ) !void {
115 _ = unused_fmt_string;
116 _ = options;
117 const cie = ctx.cie;
118 try writer.print("@{x} : size({x})", .{
119 cie.offset,
120 cie.getSize(),
121 });
122 if (!cie.alive) try writer.writeAll(" : [*]");
123 }
92 fn default(f: Format, w: *Writer) Writer.Error!void {
93 const cie = f.cie;
94 try w.print("@{x} : size({x})", .{
95 cie.offset,
96 cie.getSize(),
97 });
98 if (!cie.alive) try w.writeAll(" : [*]");
99 }
100 };
124101
125102 pub const Index = u32;
126103
......@@ -148,12 +125,16 @@ pub const Fde = struct {
148125 const tracy = trace(@src());
149126 defer tracy.end();
150127
151 const data = fde.getData(macho_file);
152128 const object = fde.getObject(macho_file);
153129 const sect = object.sections.items(.header)[object.eh_frame_sect_index.?];
154130
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
155137 // Parse target atom index
156 const pc_begin = std.mem.readInt(i64, data[8..][0..8], .little);
157138 const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
158139 fde.atom = object.findAtom(taddr) orelse {
159140 try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
......@@ -165,7 +146,6 @@ pub const Fde = struct {
165146 fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
166147
167148 // Associate with a CIE
168 const cie_ptr = std.mem.readInt(u32, data[4..8], .little);
169149 const cie_offset = fde.offset + 4 - cie_ptr;
170150 const cie_index = for (object.cies.items, 0..) |cie, cie_index| {
171151 if (cie.offset == cie_offset) break @as(Cie.Index, @intCast(cie_index));
......@@ -183,14 +163,12 @@ pub const Fde = struct {
183163
184164 // Parse LSDA atom index if any
185165 if (cie.lsda_size) |lsda_size| {
186 var stream = std.io.fixedBufferStream(data[24..]);
187 var creader = std.io.countingReader(stream.reader());
188 const reader = creader.reader();
189 _ = try leb.readUleb128(u64, reader); // augmentation length
190 fde.lsda_ptr_offset = @intCast(creader.bytes_read + 24);
166 try br.discard(8);
167 _ = try br.takeLeb128(u64); // augmentation length
168 fde.lsda_ptr_offset = @intCast(br.seek);
191169 const lsda_ptr = switch (lsda_size) {
192 .p32 => try reader.readInt(i32, .little),
193 .p64 => try reader.readInt(i64, .little),
170 .p32 => try br.takeInt(i32, .little),
171 .p64 => try br.takeInt(i64, .little),
194172 };
195173 const lsda_addr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + fde.lsda_ptr_offset)) + lsda_ptr);
196174 fde.lsda = object.findAtom(lsda_addr) orelse {
......@@ -231,56 +209,35 @@ pub const Fde = struct {
231209 return fde.getObject(macho_file).getAtom(fde.lsda);
232210 }
233211
234 pub fn format(
235 fde: Fde,
236 comptime unused_fmt_string: []const u8,
237 options: std.fmt.FormatOptions,
238 writer: anytype,
239 ) !void {
240 _ = fde;
241 _ = unused_fmt_string;
242 _ = options;
243 _ = writer;
244 @compileError("do not format FDEs directly");
245 }
246
247 pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(format2) {
212 pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
248213 return .{ .data = .{
249214 .fde = fde,
250215 .macho_file = macho_file,
251216 } };
252217 }
253218
254 const FormatContext = struct {
219 const Format = struct {
255220 fde: Fde,
256221 macho_file: *MachO,
257 };
258222
259 fn format2(
260 ctx: FormatContext,
261 comptime unused_fmt_string: []const u8,
262 options: std.fmt.FormatOptions,
263 writer: anytype,
264 ) !void {
265 _ = unused_fmt_string;
266 _ = options;
267 const fde = ctx.fde;
268 const macho_file = ctx.macho_file;
269 try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
270 fde.offset,
271 fde.getSize(),
272 fde.cie,
273 fde.getAtom(macho_file).getName(macho_file),
274 });
275 if (!fde.alive) try writer.writeAll(" : [*]");
276 }
223 fn default(f: Format, w: *Writer) Writer.Error!void {
224 const fde = f.fde;
225 const macho_file = f.macho_file;
226 try w.print("@{x} : size({x}) : cie({d}) : {s}", .{
227 fde.offset,
228 fde.getSize(),
229 fde.cie,
230 fde.getAtom(macho_file).getName(macho_file),
231 });
232 if (!fde.alive) try w.writeAll(" : [*]");
233 }
234 };
277235
278236 pub const Index = u32;
279237};
280238
281239pub const Iterator = struct {
282 data: []const u8,
283 pos: u32 = 0,
240 reader: *std.io.Reader,
284241
285242 pub const Record = struct {
286243 tag: enum { fde, cie },
......@@ -289,21 +246,19 @@ pub const Iterator = struct {
289246 };
290247
291248 pub fn next(it: *Iterator) !?Record {
292 if (it.pos >= it.data.len) return null;
293
294 var stream = std.io.fixedBufferStream(it.data[it.pos..]);
295 const reader = stream.reader();
249 const r = it.reader;
250 if (r.seek >= r.storageBuffer().len) return null;
296251
297 const size = try reader.readInt(u32, .little);
252 const size = try r.takeInt(u32, .little);
298253 if (size == 0xFFFFFFFF) @panic("DWARF CFI is 32bit on macOS");
299254
300 const id = try reader.readInt(u32, .little);
301 const record = Record{
255 const id = try r.takeInt(u32, .little);
256 const record: Record = .{
302257 .tag = if (id == 0) .cie else .fde,
303 .offset = it.pos,
258 .offset = @intCast(r.seek),
304259 .size = size,
305260 };
306 it.pos += size + 4;
261 try r.discard(size);
307262
308263 return record;
309264 }
......@@ -545,6 +500,7 @@ const math = std.math;
545500const mem = std.mem;
546501const std = @import("std");
547502const trace = @import("../../tracy.zig").trace;
503const Writer = std.io.Writer;
548504
549505const Allocator = std.mem.Allocator;
550506const Atom = @import("Atom.zig");
src/link/MachO/file.zig+9-8
......@@ -14,12 +14,12 @@ pub const File = union(enum) {
1414 return .{ .data = file };
1515 }
1616
17 fn formatPath(file: File, writer: *std.io.Writer) std.io.Writer.Error!void {
17 fn formatPath(file: File, w: *Writer) Writer.Error!void {
1818 switch (file) {
19 .zig_object => |zo| try writer.writeAll(zo.basename),
20 .internal => try writer.writeAll("internal"),
21 .object => |x| try writer.print("{}", .{x.fmtPath()}),
22 .dylib => |dl| try writer.print("{}", .{@as(Path, dl.path)}),
19 .zig_object => |zo| try w.writeAll(zo.basename),
20 .internal => try w.writeAll("internal"),
21 .object => |x| try w.print("{f}", .{x.fmtPath()}),
22 .dylib => |dl| try w.print("{f}", .{@as(Path, dl.path)}),
2323 }
2424 }
2525
......@@ -321,11 +321,11 @@ pub const File = union(enum) {
321321 };
322322 }
323323
324 pub fn writeAr(file: File, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
324 pub fn writeAr(file: File, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) Writer.Error!void {
325325 return switch (file) {
326326 .dylib, .internal => unreachable,
327 .zig_object => |x| x.writeAr(ar_format, writer),
328 .object => |x| x.writeAr(ar_format, macho_file, writer),
327 .zig_object => |x| x.writeAr(bw, ar_format),
328 .object => |x| x.writeAr(bw, ar_format, macho_file),
329329 };
330330 }
331331
......@@ -364,6 +364,7 @@ const log = std.log.scoped(.link);
364364const macho = std.macho;
365365const Allocator = std.mem.Allocator;
366366const Path = std.Build.Cache.Path;
367const Writer = std.io.Writer;
367368
368369const trace = @import("../../tracy.zig").trace;
369370const Archive = @import("Archive.zig");
src/link/MachO/load_commands.zig+22-30
......@@ -3,6 +3,7 @@ const assert = std.debug.assert;
33const log = std.log.scoped(.link);
44const macho = std.macho;
55const mem = std.mem;
6const Writer = std.io.Writer;
67
78const Allocator = mem.Allocator;
89const DebugSymbols = @import("DebugSymbols.zig");
......@@ -180,23 +181,20 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
180181 return offset;
181182}
182183
183pub fn writeDylinkerLC(writer: anytype) !void {
184pub fn writeDylinkerLC(bw: *Writer) Writer.Error!void {
184185 const name_len = mem.sliceTo(default_dyld_path, 0).len;
185186 const cmdsize = @as(u32, @intCast(mem.alignForward(
186187 u64,
187188 @sizeOf(macho.dylinker_command) + name_len,
188189 @sizeOf(u64),
189190 )));
190 try writer.writeStruct(macho.dylinker_command{
191 try bw.writeStruct(macho.dylinker_command{
191192 .cmd = .LOAD_DYLINKER,
192193 .cmdsize = cmdsize,
193194 .name = @sizeOf(macho.dylinker_command),
194195 });
195 try writer.writeAll(mem.sliceTo(default_dyld_path, 0));
196 const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;
197 if (padding > 0) {
198 try writer.writeByteNTimes(0, padding);
199 }
196 try bw.writeAll(mem.sliceTo(default_dyld_path, 0));
197 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylinker_command) - name_len);
200198}
201199
202200const WriteDylibLCCtx = struct {
......@@ -207,14 +205,14 @@ const WriteDylibLCCtx = struct {
207205 compatibility_version: u32 = 0x10000,
208206};
209207
210pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
208pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {
211209 const name_len = ctx.name.len + 1;
212 const cmdsize = @as(u32, @intCast(mem.alignForward(
210 const cmdsize: u32 = @intCast(mem.alignForward(
213211 u64,
214212 @sizeOf(macho.dylib_command) + name_len,
215213 @sizeOf(u64),
216 )));
217 try writer.writeStruct(macho.dylib_command{
214 ));
215 try bw.writeStruct(macho.dylib_command{
218216 .cmd = ctx.cmd,
219217 .cmdsize = cmdsize,
220218 .dylib = .{
......@@ -224,12 +222,9 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
224222 .compatibility_version = ctx.compatibility_version,
225223 },
226224 });
227 try writer.writeAll(ctx.name);
228 try writer.writeByte(0);
229 const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;
230 if (padding > 0) {
231 try writer.writeByteNTimes(0, padding);
232 }
225 try bw.writeAll(ctx.name);
226 try bw.writeByte(0);
227 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylib_command) - name_len);
233228}
234229
235230pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
......@@ -258,26 +253,23 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
258253 }, writer);
259254}
260255
261pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {
256pub fn writeRpathLC(bw: *Writer, rpath: []const u8) !void {
262257 const rpath_len = rpath.len + 1;
263258 const cmdsize = @as(u32, @intCast(mem.alignForward(
264259 u64,
265260 @sizeOf(macho.rpath_command) + rpath_len,
266261 @sizeOf(u64),
267262 )));
268 try writer.writeStruct(macho.rpath_command{
263 try bw.writeStruct(macho.rpath_command{
269264 .cmdsize = cmdsize,
270265 .path = @sizeOf(macho.rpath_command),
271266 });
272 try writer.writeAll(rpath);
273 try writer.writeByte(0);
274 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;
275 if (padding > 0) {
276 try writer.writeByteNTimes(0, padding);
277 }
267 try bw.writeAll(rpath);
268 try bw.writeByte(0);
269 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.rpath_command) - rpath_len);
278270}
279271
280pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {
272pub fn writeVersionMinLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) Writer.Error!void {
281273 const cmd: macho.LC = switch (platform.os_tag) {
282274 .macos => .VERSION_MIN_MACOSX,
283275 .ios => .VERSION_MIN_IPHONEOS,
......@@ -285,7 +277,7 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer
285277 .watchos => .VERSION_MIN_WATCHOS,
286278 else => unreachable,
287279 };
288 try writer.writeAll(mem.asBytes(&macho.version_min_command{
280 try bw.writeAll(mem.asBytes(&macho.version_min_command{
289281 .cmd = cmd,
290282 .version = platform.toAppleVersion(),
291283 .sdk = if (sdk_version) |ver|
......@@ -295,9 +287,9 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer
295287 }));
296288}
297289
298pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void {
290pub fn writeBuildVersionLC(bw: *Writer, platform: MachO.Platform, sdk_version: ?std.SemanticVersion) Writer.Error!void {
299291 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
300 try writer.writeStruct(macho.build_version_command{
292 try bw.writeStruct(macho.build_version_command{
301293 .cmdsize = cmdsize,
302294 .platform = platform.toApplePlatform(),
303295 .minos = platform.toAppleVersion(),
......@@ -307,7 +299,7 @@ pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticV
307299 platform.toAppleVersion(),
308300 .ntools = 1,
309301 });
310 try writer.writeAll(mem.asBytes(&macho.build_tool_version{
302 try bw.writeAll(mem.asBytes(&macho.build_tool_version{
311303 .tool = .ZIG,
312304 .version = 0x0,
313305 }));
src/link/MachO/relocatable.zig+31-58
......@@ -20,13 +20,13 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
2020 // the *only* input file over.
2121 const path = positionals.items[0].path().?;
2222 const in_file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err|
23 return diags.fail("failed to open {}: {s}", .{ path, @errorName(err) });
23 return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) });
2424 const stat = in_file.stat() catch |err|
25 return diags.fail("failed to stat {}: {s}", .{ path, @errorName(err) });
25 return diags.fail("failed to stat {f}: {s}", .{ path, @errorName(err) });
2626 const amt = in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size) catch |err|
27 return diags.fail("failed to copy range of file {}: {s}", .{ path, @errorName(err) });
27 return diags.fail("failed to copy range of file {f}: {s}", .{ path, @errorName(err) });
2828 if (amt != stat.size)
29 return diags.fail("unexpected short write in copy range of file {}", .{path});
29 return diags.fail("unexpected short write in copy range of file {f}", .{path});
3030 return;
3131 }
3232
......@@ -62,7 +62,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
6262 allocateSegment(macho_file);
6363
6464 if (build_options.enable_logging) {
65 state_log.debug("{}", .{macho_file.dumpState()});
65 state_log.debug("{f}", .{macho_file.dumpState()});
6666 }
6767
6868 try writeSections(macho_file);
......@@ -126,7 +126,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
126126 allocateSegment(macho_file);
127127
128128 if (build_options.enable_logging) {
129 state_log.debug("{}", .{macho_file.dumpState()});
129 state_log.debug("{f}", .{macho_file.dumpState()});
130130 }
131131
132132 try writeSections(macho_file);
......@@ -202,38 +202,30 @@ 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{}\n", .{ar_symtab.fmt(macho_file)});
205 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
206206 }
207207
208 var buffer = std.ArrayList(u8).init(gpa);
209 defer buffer.deinit();
210 try buffer.ensureTotalCapacityPrecise(total_size);
211 const writer = buffer.writer();
208 var bw: Writer = .fixed(try gpa.alloc(u8, total_size));
209 defer gpa.free(bw.buffer);
212210
213211 // Write magic
214 try writer.writeAll(Archive.ARMAG);
212 bw.writeAll(Archive.ARMAG) catch unreachable;
215213
216214 // Write symtab
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)}),
215 ar_symtab.write(&bw, format, macho_file) catch |err| {
216 return diags.fail("failed to write archive symbol table: {s}", .{@errorName(err)});
220217 };
221218
222219 // Write object files
223220 for (files.items) |index| {
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|
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|
230223 return diags.fail("failed to write archive: {s}", .{@errorName(err)});
231224 }
232225
233 assert(buffer.items.len == total_size);
234
235 try macho_file.setEndPos(total_size);
236 try macho_file.pwriteAll(buffer.items, 0);
226 assert(bw.end == bw.buffer.len);
227 try macho_file.setEndPos(bw.end);
228 try macho_file.pwriteAll(bw.buffer, 0);
237229
238230 if (diags.hasErrors()) return error.LinkFailure;
239231}
......@@ -672,7 +664,7 @@ fn writeCompactUnwindWorker(macho_file: *MachO, object: *Object) void {
672664 diags.addError("failed to write '__LD,__eh_frame' section: {s}", .{@errorName(err)});
673665}
674666
675fn writeSectionsToFile(macho_file: *MachO) !void {
667fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {
676668 const tracy = trace(@src());
677669 defer tracy.end();
678670
......@@ -689,12 +681,8 @@ fn writeSectionsToFile(macho_file: *MachO) !void {
689681
690682fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } {
691683 const gpa = macho_file.base.comp.gpa;
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();
684 var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeObject(macho_file)));
685 defer gpa.free(bw.buffer);
698686
699687 var ncmds: usize = 0;
700688
......@@ -702,47 +690,31 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
702690 {
703691 assert(macho_file.segments.items.len == 1);
704692 const seg = macho_file.segments.items[0];
705 writer.writeStruct(seg) catch |err| switch (err) {
706 error.NoSpaceLeft => unreachable,
707 };
693 bw.writeStruct(seg) catch unreachable;
708694 for (macho_file.sections.items(.header)) |header| {
709 writer.writeStruct(header) catch |err| switch (err) {
710 error.NoSpaceLeft => unreachable,
711 };
695 bw.writeStruct(header) catch unreachable;
712696 }
713697 ncmds += 1;
714698 }
715699
716 writer.writeStruct(macho_file.data_in_code_cmd) catch |err| switch (err) {
717 error.NoSpaceLeft => unreachable,
718 };
700 bw.writeStruct(macho_file.data_in_code_cmd) catch unreachable;
719701 ncmds += 1;
720 writer.writeStruct(macho_file.symtab_cmd) catch |err| switch (err) {
721 error.NoSpaceLeft => unreachable,
722 };
702 bw.writeStruct(macho_file.symtab_cmd) catch unreachable;
723703 ncmds += 1;
724 writer.writeStruct(macho_file.dysymtab_cmd) catch |err| switch (err) {
725 error.NoSpaceLeft => unreachable,
726 };
704 bw.writeStruct(macho_file.dysymtab_cmd) catch unreachable;
727705 ncmds += 1;
728706
729707 if (macho_file.platform.isBuildVersionCompatible()) {
730 load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
731 error.NoSpaceLeft => unreachable,
732 };
708 load_commands.writeBuildVersionLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable;
733709 ncmds += 1;
734710 } else {
735 load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {
736 error.NoSpaceLeft => unreachable,
737 };
711 load_commands.writeVersionMinLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable;
738712 ncmds += 1;
739713 }
740714
741 assert(stream.pos == needed_size);
742
743 try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
744
745 return .{ ncmds, buffer.len };
715 assert(bw.end == bw.buffer.len);
716 try macho_file.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
717 return .{ ncmds, bw.end };
746718}
747719
748720fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
......@@ -784,6 +756,7 @@ const macho = std.macho;
784756const math = std.math;
785757const mem = std.mem;
786758const state_log = std.log.scoped(.link_state);
759const Writer = std.io.Writer;
787760
788761const Archive = @import("Archive.zig");
789762const Atom = @import("Atom.zig");
src/link/MachO/synthetic.zig+124-151
......@@ -27,44 +27,37 @@ pub const GotSection = struct {
2727 return got.symbols.items.len * @sizeOf(u64);
2828 }
2929
30 pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void {
30 pub fn write(got: GotSection, macho_file: *MachO, bw: *Writer) !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 writer.writeInt(u64, value, .little);
36 try bw.writeInt(u64, value, .little);
3737 }
3838 }
3939
40 const FormatCtx = struct {
40 const Format = struct {
4141 got: GotSection,
4242 macho_file: *MachO,
43
44 pub fn print(f: Format, w: *Writer) Writer.Error!void {
45 for (f.got.symbols.items, 0..) |ref, i| {
46 const symbol = ref.getSymbol(f.macho_file).?;
47 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
48 i,
49 symbol.getGotAddress(f.macho_file),
50 ref,
51 symbol.getAddress(.{}, f.macho_file),
52 symbol.getName(f.macho_file),
53 });
54 }
55 }
4356 };
4457
45 pub fn fmt(got: GotSection, macho_file: *MachO) std.fmt.Formatter(format2) {
58 pub fn fmt(got: GotSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
4659 return .{ .data = .{ .got = got, .macho_file = macho_file } };
4760 }
48
49 pub fn format2(
50 ctx: FormatCtx,
51 comptime unused_fmt_string: []const u8,
52 options: std.fmt.FormatOptions,
53 writer: anytype,
54 ) !void {
55 _ = options;
56 _ = unused_fmt_string;
57 for (ctx.got.symbols.items, 0..) |ref, i| {
58 const symbol = ref.getSymbol(ctx.macho_file).?;
59 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
60 i,
61 symbol.getGotAddress(ctx.macho_file),
62 ref,
63 symbol.getAddress(.{}, ctx.macho_file),
64 symbol.getName(ctx.macho_file),
65 });
66 }
67 }
6861};
6962
7063pub const StubsSection = struct {
......@@ -96,7 +89,7 @@ pub const StubsSection = struct {
9689 return stubs.symbols.items.len * header.reserved2;
9790 }
9891
99 pub fn write(stubs: StubsSection, macho_file: *MachO, writer: anytype) !void {
92 pub fn write(stubs: StubsSection, macho_file: *MachO, bw: *Writer) !void {
10093 const tracy = trace(@src());
10194 defer tracy.end();
10295 const cpu_arch = macho_file.getTarget().cpu.arch;
......@@ -108,54 +101,47 @@ pub const StubsSection = struct {
108101 const target = laptr_sect.addr + idx * @sizeOf(u64);
109102 switch (cpu_arch) {
110103 .x86_64 => {
111 try writer.writeAll(&.{ 0xff, 0x25 });
112 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
104 try bw.writeAll(&.{ 0xff, 0x25 });
105 try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little);
113106 },
114107 .aarch64 => {
115108 // TODO relax if possible
116109 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
117 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
110 try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
118111 const off = try math.divExact(u12, @truncate(target), 8);
119 try writer.writeInt(
112 try bw.writeInt(
120113 u32,
121114 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
122115 .little,
123116 );
124 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
117 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
125118 },
126119 else => unreachable,
127120 }
128121 }
129122 }
130123
131 const FormatCtx = struct {
132 stubs: StubsSection,
133 macho_file: *MachO,
134 };
135
136 pub fn fmt(stubs: StubsSection, macho_file: *MachO) std.fmt.Formatter(format2) {
124 pub fn fmt(stubs: StubsSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
137125 return .{ .data = .{ .stubs = stubs, .macho_file = macho_file } };
138126 }
139127
140 pub fn format2(
141 ctx: FormatCtx,
142 comptime unused_fmt_string: []const u8,
143 options: std.fmt.FormatOptions,
144 writer: anytype,
145 ) !void {
146 _ = options;
147 _ = unused_fmt_string;
148 for (ctx.stubs.symbols.items, 0..) |ref, i| {
149 const symbol = ref.getSymbol(ctx.macho_file).?;
150 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
151 i,
152 symbol.getStubsAddress(ctx.macho_file),
153 ref,
154 symbol.getAddress(.{}, ctx.macho_file),
155 symbol.getName(ctx.macho_file),
156 });
128 const Format = struct {
129 stubs: StubsSection,
130 macho_file: *MachO,
131
132 pub fn print(f: Format, w: *Writer) Writer.Error!void {
133 for (f.stubs.symbols.items, 0..) |ref, i| {
134 const symbol = ref.getSymbol(f.macho_file).?;
135 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
136 i,
137 symbol.getStubsAddress(f.macho_file),
138 ref,
139 symbol.getAddress(.{}, f.macho_file),
140 symbol.getName(f.macho_file),
141 });
142 }
157143 }
158 }
144 };
159145};
160146
161147pub const StubsHelperSection = struct {
......@@ -189,11 +175,11 @@ pub const StubsHelperSection = struct {
189175 return s;
190176 }
191177
192 pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
178 pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void {
193179 const tracy = trace(@src());
194180 defer tracy.end();
195181
196 try stubs_helper.writePreamble(macho_file, writer);
182 try stubs_helper.writePreamble(macho_file, bw);
197183
198184 const cpu_arch = macho_file.getTarget().cpu.arch;
199185 const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
......@@ -209,24 +195,24 @@ pub const StubsHelperSection = struct {
209195 const target: i64 = @intCast(sect.addr);
210196 switch (cpu_arch) {
211197 .x86_64 => {
212 try writer.writeByte(0x68);
213 try writer.writeInt(u32, offset, .little);
214 try writer.writeByte(0xe9);
215 try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);
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);
216202 },
217203 .aarch64 => {
218204 const literal = blk: {
219205 const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);
220206 break :blk std.math.cast(u18, div_res) orelse return error.Overflow;
221207 };
222 try writer.writeInt(u32, aarch64.Instruction.ldrLiteral(
208 try bw.writeInt(u32, aarch64.Instruction.ldrLiteral(
223209 .w16,
224210 literal,
225211 ).toU32(), .little);
226212 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse
227213 return error.Overflow;
228 try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
229 try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
214 try bw.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
215 try bw.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
230216 },
231217 else => unreachable,
232218 }
......@@ -234,7 +220,7 @@ pub const StubsHelperSection = struct {
234220 }
235221 }
236222
237 fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: anytype) !void {
223 fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void {
238224 _ = stubs_helper;
239225 const obj = macho_file.getInternalObject().?;
240226 const cpu_arch = macho_file.getTarget().cpu.arch;
......@@ -249,21 +235,21 @@ pub const StubsHelperSection = struct {
249235 };
250236 switch (cpu_arch) {
251237 .x86_64 => {
252 try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d });
253 try writer.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);
254 try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
255 try writer.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);
256 try writer.writeByte(0x90);
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);
257243 },
258244 .aarch64 => {
259245 {
260246 // TODO relax if possible
261247 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));
262 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
248 try bw.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
263249 const off: u12 = @truncate(dyld_private_addr);
264 try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
250 try bw.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
265251 }
266 try writer.writeInt(u32, aarch64.Instruction.stp(
252 try bw.writeInt(u32, aarch64.Instruction.stp(
267253 .x16,
268254 .x17,
269255 aarch64.Register.sp,
......@@ -272,15 +258,15 @@ pub const StubsHelperSection = struct {
272258 {
273259 // TODO relax if possible
274260 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));
275 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
261 try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
276262 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);
277 try writer.writeInt(u32, aarch64.Instruction.ldr(
263 try bw.writeInt(u32, aarch64.Instruction.ldr(
278264 .x16,
279265 .x16,
280266 aarch64.Instruction.LoadStoreOffset.imm(off),
281267 ).toU32(), .little);
282268 }
283 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
269 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
284270 },
285271 else => unreachable,
286272 }
......@@ -293,7 +279,7 @@ pub const LaSymbolPtrSection = struct {
293279 return macho_file.stubs.symbols.items.len * @sizeOf(u64);
294280 }
295281
296 pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: anytype) !void {
282 pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, bw: *Writer) !void {
297283 const tracy = trace(@src());
298284 defer tracy.end();
299285 _ = laptr;
......@@ -304,12 +290,12 @@ pub const LaSymbolPtrSection = struct {
304290 const sym = ref.getSymbol(macho_file).?;
305291 if (sym.flags.weak) {
306292 const value = sym.getAddress(.{ .stubs = false }, macho_file);
307 try writer.writeInt(u64, @intCast(value), .little);
293 try bw.writeInt(u64, @intCast(value), .little);
308294 } else {
309295 const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) +
310296 StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx;
311297 stub_helper_idx += 1;
312 try writer.writeInt(u64, @intCast(value), .little);
298 try bw.writeInt(u64, @intCast(value), .little);
313299 }
314300 }
315301 }
......@@ -343,48 +329,41 @@ pub const TlvPtrSection = struct {
343329 return tlv.symbols.items.len * @sizeOf(u64);
344330 }
345331
346 pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: anytype) !void {
332 pub fn write(tlv: TlvPtrSection, macho_file: *MachO, bw: *Writer) !void {
347333 const tracy = trace(@src());
348334 defer tracy.end();
349335
350336 for (tlv.symbols.items) |ref| {
351337 const sym = ref.getSymbol(macho_file).?;
352338 if (sym.flags.import) {
353 try writer.writeInt(u64, 0, .little);
339 try bw.writeInt(u64, 0, .little);
354340 } else {
355 try writer.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
341 try bw.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
356342 }
357343 }
358344 }
359345
360 const FormatCtx = struct {
361 tlv: TlvPtrSection,
362 macho_file: *MachO,
363 };
364
365 pub fn fmt(tlv: TlvPtrSection, macho_file: *MachO) std.fmt.Formatter(format2) {
346 pub fn fmt(tlv: TlvPtrSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
366347 return .{ .data = .{ .tlv = tlv, .macho_file = macho_file } };
367348 }
368349
369 pub fn format2(
370 ctx: FormatCtx,
371 comptime unused_fmt_string: []const u8,
372 options: std.fmt.FormatOptions,
373 writer: anytype,
374 ) !void {
375 _ = options;
376 _ = unused_fmt_string;
377 for (ctx.tlv.symbols.items, 0..) |ref, i| {
378 const symbol = ref.getSymbol(ctx.macho_file).?;
379 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
380 i,
381 symbol.getTlvPtrAddress(ctx.macho_file),
382 ref,
383 symbol.getAddress(.{}, ctx.macho_file),
384 symbol.getName(ctx.macho_file),
385 });
350 const Format = struct {
351 tlv: TlvPtrSection,
352 macho_file: *MachO,
353
354 pub fn print(f: Format, w: *Writer) Writer.Error!void {
355 for (f.tlv.symbols.items, 0..) |ref, i| {
356 const symbol = ref.getSymbol(f.macho_file).?;
357 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
358 i,
359 symbol.getTlvPtrAddress(f.macho_file),
360 ref,
361 symbol.getAddress(.{}, f.macho_file),
362 symbol.getName(f.macho_file),
363 });
364 }
386365 }
387 }
366 };
388367};
389368
390369pub const ObjcStubsSection = struct {
......@@ -421,7 +400,7 @@ pub const ObjcStubsSection = struct {
421400 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
422401 }
423402
424 pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: anytype) !void {
403 pub fn write(objc: ObjcStubsSection, macho_file: *MachO, bw: *Writer) !void {
425404 const tracy = trace(@src());
426405 defer tracy.end();
427406
......@@ -432,18 +411,18 @@ pub const ObjcStubsSection = struct {
432411 const addr = objc.getAddress(@intCast(idx), macho_file);
433412 switch (macho_file.getTarget().cpu.arch) {
434413 .x86_64 => {
435 try writer.writeAll(&.{ 0x48, 0x8b, 0x35 });
414 try bw.writeAll(&.{ 0x48, 0x8b, 0x35 });
436415 {
437416 const target = sym.getObjcSelrefsAddress(macho_file);
438417 const source = addr;
439 try writer.writeInt(i32, @intCast(target - source - 3 - 4), .little);
418 try bw.writeInt(i32, @intCast(target - source - 3 - 4), .little);
440419 }
441 try writer.writeAll(&.{ 0xff, 0x25 });
420 try bw.writeAll(&.{ 0xff, 0x25 });
442421 {
443422 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
444423 const target = target_sym.getGotAddress(macho_file);
445424 const source = addr + 7;
446 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
425 try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little);
447426 }
448427 },
449428 .aarch64 => {
......@@ -451,9 +430,9 @@ pub const ObjcStubsSection = struct {
451430 const target = sym.getObjcSelrefsAddress(macho_file);
452431 const source = addr;
453432 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
454 try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
433 try bw.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
455434 const off = try math.divExact(u12, @truncate(target), 8);
456 try writer.writeInt(
435 try bw.writeInt(
457436 u32,
458437 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
459438 .little,
......@@ -464,52 +443,45 @@ pub const ObjcStubsSection = struct {
464443 const target = target_sym.getGotAddress(macho_file);
465444 const source = addr + 2 * @sizeOf(u32);
466445 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
467 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
446 try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
468447 const off = try math.divExact(u12, @truncate(target), 8);
469 try writer.writeInt(
448 try bw.writeInt(
470449 u32,
471450 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
472451 .little,
473452 );
474453 }
475 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
476 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
477 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
478 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
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);
479458 },
480459 else => unreachable,
481460 }
482461 }
483462 }
484463
485 const FormatCtx = struct {
486 objc: ObjcStubsSection,
487 macho_file: *MachO,
488 };
489
490 pub fn fmt(objc: ObjcStubsSection, macho_file: *MachO) std.fmt.Formatter(format2) {
464 pub fn fmt(objc: ObjcStubsSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
491465 return .{ .data = .{ .objc = objc, .macho_file = macho_file } };
492466 }
493467
494 pub fn format2(
495 ctx: FormatCtx,
496 comptime unused_fmt_string: []const u8,
497 options: std.fmt.FormatOptions,
498 writer: anytype,
499 ) !void {
500 _ = options;
501 _ = unused_fmt_string;
502 for (ctx.objc.symbols.items, 0..) |ref, i| {
503 const symbol = ref.getSymbol(ctx.macho_file).?;
504 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
505 i,
506 symbol.getObjcStubsAddress(ctx.macho_file),
507 ref,
508 symbol.getAddress(.{}, ctx.macho_file),
509 symbol.getName(ctx.macho_file),
510 });
468 const Format = struct {
469 objc: ObjcStubsSection,
470 macho_file: *MachO,
471
472 pub fn print(f: Format, w: *Writer) Writer.Error!void {
473 for (f.objc.symbols.items, 0..) |ref, i| {
474 const symbol = ref.getSymbol(f.macho_file).?;
475 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
476 i,
477 symbol.getObjcStubsAddress(f.macho_file),
478 ref,
479 symbol.getAddress(.{}, f.macho_file),
480 symbol.getName(f.macho_file),
481 });
482 }
511483 }
512 }
484 };
513485
514486 pub const Index = u32;
515487};
......@@ -524,7 +496,7 @@ pub const Indsymtab = struct {
524496 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
525497 }
526498
527 pub fn write(ind: Indsymtab, macho_file: *MachO, writer: anytype) !void {
499 pub fn write(ind: Indsymtab, macho_file: *MachO, bw: *Writer) !void {
528500 const tracy = trace(@src());
529501 defer tracy.end();
530502
......@@ -533,21 +505,21 @@ pub const Indsymtab = struct {
533505 for (macho_file.stubs.symbols.items) |ref| {
534506 const sym = ref.getSymbol(macho_file).?;
535507 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
536 try writer.writeInt(u32, idx, .little);
508 try bw.writeInt(u32, idx, .little);
537509 }
538510 }
539511
540512 for (macho_file.got.symbols.items) |ref| {
541513 const sym = ref.getSymbol(macho_file).?;
542514 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
543 try writer.writeInt(u32, idx, .little);
515 try bw.writeInt(u32, idx, .little);
544516 }
545517 }
546518
547519 for (macho_file.stubs.symbols.items) |ref| {
548520 const sym = ref.getSymbol(macho_file).?;
549521 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
550 try writer.writeInt(u32, idx, .little);
522 try bw.writeInt(u32, idx, .little);
551523 }
552524 }
553525 }
......@@ -601,7 +573,7 @@ pub const DataInCode = struct {
601573 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;
602574 }
603575
604 pub fn write(dice: DataInCode, macho_file: *MachO, writer: anytype) !void {
576 pub fn write(dice: DataInCode, macho_file: *MachO, bw: *Writer) !void {
605577 const base_address = if (!macho_file.base.isRelocatable())
606578 macho_file.getTextSegment().vmaddr
607579 else
......@@ -609,7 +581,7 @@ pub const DataInCode = struct {
609581 for (dice.entries.items) |entry| {
610582 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);
611583 const offset = atom_address + entry.offset - base_address;
612 try writer.writeStruct(macho.data_in_code_entry{
584 try bw.writeStruct(macho.data_in_code_entry{
613585 .offset = @intCast(offset),
614586 .length = entry.length,
615587 .kind = entry.kind,
......@@ -625,13 +597,14 @@ pub const DataInCode = struct {
625597 };
626598};
627599
600const std = @import("std");
628601const aarch64 = @import("../aarch64.zig");
629602const assert = std.debug.assert;
630603const macho = std.macho;
631604const math = std.math;
632const std = @import("std");
633const trace = @import("../../tracy.zig").trace;
634
635605const Allocator = std.mem.Allocator;
606const Writer = std.io.Writer;
607
608const trace = @import("../../tracy.zig").trace;
636609const MachO = @import("../MachO.zig");
637610const Symbol = @import("Symbol.zig");