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 {...@@ -444,7 +444,7 @@ pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void {
444 printRt(m, prop.msg, .{"{s}"}, .{&str});444 printRt(m, prop.msg, .{"{s}"}, .{&str});
445 } else {445 } else {
446 var buf: [3]u8 = undefined;446 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;
448 printRt(m, prop.msg, .{"{s}"}, .{str});448 printRt(m, prop.msg, .{"{s}"}, .{str});
449 }449 }
450 },450 },
...@@ -525,13 +525,13 @@ fn tagKind(d: *Diagnostics, tag: Tag, langopts: LangOpts) Kind {...@@ -525,13 +525,13 @@ fn tagKind(d: *Diagnostics, tag: Tag, langopts: LangOpts) Kind {
525}525}
526526
527const MsgWriter = struct {527const MsgWriter = struct {
528 w: std.io.BufferedWriter(4096, std.fs.File.Writer),528 w: *std.fs.File.Writer,
529 config: std.io.tty.Config,529 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 {
532 std.debug.lockStdErr();532 std.debug.lockStdErr();
533 return .{533 return .{
534 .w = std.io.bufferedWriter(std.fs.File.stderr().deprecatedWriter()),534 .w = std.fs.stderr().writer(buffer),
535 .config = config,535 .config = config,
536 };536 };
537 }537 }
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 },...@@ -41,9 +41,9 @@ data_in_code_cmd: macho.linkedit_data_command = .{ .cmd = .DATA_IN_CODE },
41uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },41uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 },
42codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },42codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },
4343
44pagezero_seg_index: ?u8 = null,44pagezero_seg_index: ?u4 = null,
45text_seg_index: ?u8 = null,45text_seg_index: ?u4 = null,
46linkedit_seg_index: ?u8 = null,46linkedit_seg_index: ?u4 = null,
47text_sect_index: ?u8 = null,47text_sect_index: ?u8 = null,
48data_sect_index: ?u8 = null,48data_sect_index: ?u8 = null,
49got_sect_index: ?u8 = null,49got_sect_index: ?u8 = null,
...@@ -76,10 +76,10 @@ unwind_info: UnwindInfo = .{},...@@ -76,10 +76,10 @@ unwind_info: UnwindInfo = .{},
76data_in_code: DataInCode = .{},76data_in_code: DataInCode = .{},
7777
78/// Tracked loadable segments during incremental linking.78/// Tracked loadable segments during incremental linking.
79zig_text_seg_index: ?u8 = null,79zig_text_seg_index: ?u4 = null,
80zig_const_seg_index: ?u8 = null,80zig_const_seg_index: ?u4 = null,
81zig_data_seg_index: ?u8 = null,81zig_data_seg_index: ?u4 = null,
82zig_bss_seg_index: ?u8 = null,82zig_bss_seg_index: ?u4 = null,
8383
84/// Tracked section headers with incremental updates to Zig object.84/// Tracked section headers with incremental updates to Zig object.
85zig_text_sect_index: ?u8 = null,85zig_text_sect_index: ?u8 = null,
...@@ -543,7 +543,7 @@ pub fn flush(...@@ -543,7 +543,7 @@ pub fn flush(
543 self.allocateSyntheticSymbols();543 self.allocateSyntheticSymbols();
544544
545 if (build_options.enable_logging) {545 if (build_options.enable_logging) {
546 state_log.debug("{}", .{self.dumpState()});546 state_log.debug("{f}", .{self.dumpState()});
547 }547 }
548548
549 // Beyond this point, everything has been allocated a virtual address and we can resolve549 // Beyond this point, everything has been allocated a virtual address and we can resolve
...@@ -591,6 +591,7 @@ pub fn flush(...@@ -591,6 +591,7 @@ pub fn flush(
591 error.NoSpaceLeft => unreachable,591 error.NoSpaceLeft => unreachable,
592 error.OutOfMemory => return error.OutOfMemory,592 error.OutOfMemory => return error.OutOfMemory,
593 error.LinkFailure => return error.LinkFailure,593 error.LinkFailure => return error.LinkFailure,
594 else => unreachable,
594 };595 };
595 try self.writeHeader(ncmds, sizeofcmds);596 try self.writeHeader(ncmds, sizeofcmds);
596 self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) {597 self.writeUuid(uuid_cmd_offset, self.requiresCodeSig()) catch |err| switch (err) {
...@@ -677,12 +678,12 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -677,12 +678,12 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
677678
678 try argv.append("-platform_version");679 try argv.append("-platform_version");
679 try argv.append(@tagName(self.platform.os_tag));680 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
682 if (self.sdk_version) |ver| {683 if (self.sdk_version) |ver| {
683 try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}", .{ ver.major, ver.minor }));684 try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}", .{ ver.major, ver.minor }));
684 } else {685 } 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}));
686 }687 }
687688
688 if (comp.sysroot) |syslibroot| {689 if (comp.sysroot) |syslibroot| {
...@@ -863,7 +864,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {...@@ -863,7 +864,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {
863864
864 const path, const file = input.pathAndFile().?;865 const path, const file = input.pathAndFile().?;
865 // TODO don't classify now, it's too late. The input file has already been classified866 // 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
868 const fh = try self.addFileHandle(file);869 const fh = try self.addFileHandle(file);
869 var buffer: [Archive.SARMAG]u8 = undefined;870 var buffer: [Archive.SARMAG]u8 = undefined;
...@@ -1074,7 +1075,7 @@ fn accessLibPath(...@@ -1074,7 +1075,7 @@ fn accessLibPath(
10741075
1075 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1076 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1076 test_path.clearRetainingCapacity();1077 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 });
1078 try checked_paths.append(try arena.dupe(u8, test_path.items));1079 try checked_paths.append(try arena.dupe(u8, test_path.items));
1079 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {1080 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
1080 error.FileNotFound => continue,1081 error.FileNotFound => continue,
...@@ -1097,7 +1098,7 @@ fn accessFrameworkPath(...@@ -1097,7 +1098,7 @@ fn accessFrameworkPath(
10971098
1098 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1099 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1099 test_path.clearRetainingCapacity();1100 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}", .{
1101 search_dir,1102 search_dir,
1102 name,1103 name,
1103 name,1104 name,
...@@ -1178,9 +1179,9 @@ fn parseDependentDylibs(self: *MachO) !void {...@@ -1178,9 +1179,9 @@ fn parseDependentDylibs(self: *MachO) !void {
1178 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {1179 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1179 test_path.clearRetainingCapacity();1180 test_path.clearRetainingCapacity();
1180 if (self.base.comp.sysroot) |root| {1181 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 });
1182 } else {1183 } else {
1183 try test_path.writer().print("{s}{s}", .{ path, ext });1184 try test_path.print("{s}{s}", .{ path, ext });
1184 }1185 }
1185 try checked_paths.append(try arena.dupe(u8, test_path.items));1186 try checked_paths.append(try arena.dupe(u8, test_path.items));
1186 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {1187 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
...@@ -1591,7 +1592,7 @@ fn reportUndefs(self: *MachO) !void {...@@ -1591,7 +1592,7 @@ fn reportUndefs(self: *MachO) !void {
1591 const ref = refs.items[inote];1592 const ref = refs.items[inote];
1592 const file = self.getFile(ref.file).?;1593 const file = self.getFile(ref.file).?;
1593 const atom = ref.getAtom(self).?;1594 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) });
1595 }1596 }
15961597
1597 if (refs.items.len > max_notes) {1598 if (refs.items.len > max_notes) {
...@@ -2131,7 +2132,7 @@ fn initSegments(self: *MachO) !void {...@@ -2131,7 +2132,7 @@ fn initSegments(self: *MachO) !void {
21312132
2132 mem.sort(Entry, entries.items, self, Entry.lessThan);2133 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);
2135 defer gpa.free(backlinks);2136 defer gpa.free(backlinks);
2136 for (entries.items, 0..) |entry, i| {2137 for (entries.items, 0..) |entry, i| {
2137 backlinks[entry.index] = @intCast(i);2138 backlinks[entry.index] = @intCast(i);
...@@ -2145,7 +2146,7 @@ fn initSegments(self: *MachO) !void {...@@ -2145,7 +2146,7 @@ fn initSegments(self: *MachO) !void {
2145 self.segments.appendAssumeCapacity(segments[sorted.index]);2146 self.segments.appendAssumeCapacity(segments[sorted.index]);
2146 }2147 }
21472148
2148 for (&[_]*?u8{2149 for (&[_]*?u4{
2149 &self.pagezero_seg_index,2150 &self.pagezero_seg_index,
2150 &self.text_seg_index,2151 &self.text_seg_index,
2151 &self.linkedit_seg_index,2152 &self.linkedit_seg_index,
...@@ -2163,7 +2164,7 @@ fn initSegments(self: *MachO) !void {...@@ -2163,7 +2164,7 @@ fn initSegments(self: *MachO) !void {
2163 for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| {2164 for (slice.items(.header), slice.items(.segment_id)) |header, *seg_id| {
2164 const segname = header.segName();2165 const segname = header.segName();
2165 const segment_id = self.getSegmentByName(segname) orelse blk: {2166 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);
2167 const protection = getSegmentProt(segname);2168 const protection = getSegmentProt(segname);
2168 try self.segments.append(gpa, .{2169 try self.segments.append(gpa, .{
2169 .cmdsize = @sizeOf(macho.segment_command_64),2170 .cmdsize = @sizeOf(macho.segment_command_64),
...@@ -2526,10 +2527,8 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {...@@ -2526,10 +2527,8 @@ fn writeThunkWorker(self: *MachO, thunk: Thunk) void {
25262527
2527 const doWork = struct {2528 const doWork = struct {
2528 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {2529 fn doWork(th: Thunk, buffer: []u8, macho_file: *MachO) !void {
2529 const off = try macho_file.cast(usize, th.value);2530 var bw: Writer = .fixed(buffer[try macho_file.cast(usize, th.value)..][0..th.size()]);
2530 const size = th.size();2531 try th.write(macho_file, &bw);
2531 var stream = std.io.fixedBufferStream(buffer[off..][0..size]);
2532 try th.write(macho_file, stream.writer());
2533 }2532 }
2534 }.doWork;2533 }.doWork;
2535 const out = self.sections.items(.out)[thunk.out_n_sect].items;2534 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 {...@@ -2556,15 +2555,15 @@ fn writeSyntheticSectionWorker(self: *MachO, sect_id: u8, out: []u8) void {
25562555
2557 const doWork = struct {2556 const doWork = struct {
2558 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {2557 fn doWork(macho_file: *MachO, tag: Tag, buffer: []u8) !void {
2559 var stream = std.io.fixedBufferStream(buffer);2558 var bw: Writer = .fixed(buffer);
2560 switch (tag) {2559 switch (tag) {
2561 .eh_frame => eh_frame.write(macho_file, buffer),2560 .eh_frame => eh_frame.write(macho_file, buffer),
2562 .unwind_info => try macho_file.unwind_info.write(macho_file, buffer),2561 .unwind_info => try macho_file.unwind_info.write(macho_file, &bw),
2563 .got => try macho_file.got.write(macho_file, stream.writer()),2562 .got => try macho_file.got.write(macho_file, &bw),
2564 .stubs => try macho_file.stubs.write(macho_file, stream.writer()),2563 .stubs => try macho_file.stubs.write(macho_file, &bw),
2565 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, stream.writer()),2564 .la_symbol_ptr => try macho_file.la_symbol_ptr.write(macho_file, &bw),
2566 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, stream.writer()),2565 .tlv_ptr => try macho_file.tlv_ptr.write(macho_file, &bw),
2567 .objc_stubs => try macho_file.objc_stubs.write(macho_file, stream.writer()),2566 .objc_stubs => try macho_file.objc_stubs.write(macho_file, &bw),
2568 }2567 }
2569 }2568 }
2570 }.doWork;2569 }.doWork;
...@@ -2605,8 +2604,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {...@@ -2605,8 +2604,8 @@ fn updateLazyBindSizeWorker(self: *MachO) void {
2605 try macho_file.lazy_bind_section.updateSize(macho_file);2604 try macho_file.lazy_bind_section.updateSize(macho_file);
2606 const sect_id = macho_file.stubs_helper_sect_index.?;2605 const sect_id = macho_file.stubs_helper_sect_index.?;
2607 const out = &macho_file.sections.items(.out)[sect_id];2606 const out = &macho_file.sections.items(.out)[sect_id];
2608 var stream = std.io.fixedBufferStream(out.items);2607 var bw: Writer = .fixed(out.items);
2609 try macho_file.stubs_helper.write(macho_file, stream.writer());2608 try macho_file.stubs_helper.write(macho_file, &bw);
2610 }2609 }
2611 }.doWork;2610 }.doWork;
2612 doWork(self) catch |err|2611 doWork(self) catch |err|
...@@ -2665,46 +2664,49 @@ fn writeDyldInfo(self: *MachO) !void {...@@ -2665,46 +2664,49 @@ fn writeDyldInfo(self: *MachO) !void {
2665 needed_size += cmd.lazy_bind_size;2664 needed_size += cmd.lazy_bind_size;
2666 needed_size += cmd.export_size;2665 needed_size += cmd.export_size;
26672666
2668 const buffer = try gpa.alloc(u8, needed_size);2667 var bw: Writer = .fixed(try gpa.alloc(u8, needed_size));
2669 defer gpa.free(buffer);2668 defer gpa.free(bw.buffer);
2670 @memset(buffer, 0);2669 @memset(bw.buffer, 0);
2671
2672 var stream = std.io.fixedBufferStream(buffer);
2673 const writer = stream.writer();
26742670
2675 try self.rebase_section.write(writer);2671 try self.rebase_section.write(&bw);
2676 try stream.seekTo(cmd.bind_off - base_off);2672 bw.end = cmd.bind_off - base_off;
2677 try self.bind_section.write(writer);2673 try self.bind_section.write(&bw);
2678 try stream.seekTo(cmd.weak_bind_off - base_off);2674 bw.end = cmd.weak_bind_off - base_off;
2679 try self.weak_bind_section.write(writer);2675 try self.weak_bind_section.write(&bw);
2680 try stream.seekTo(cmd.lazy_bind_off - base_off);2676 bw.end = cmd.lazy_bind_off - base_off;
2681 try self.lazy_bind_section.write(writer);2677 try self.lazy_bind_section.write(&bw);
2682 try stream.seekTo(cmd.export_off - base_off);2678 bw.end = cmd.export_off - base_off;
2683 try self.export_trie.write(writer);2679 try self.export_trie.write(&bw);
2684 try self.pwriteAll(buffer, cmd.rebase_off);2680 try self.pwriteAll(bw.buffer, cmd.rebase_off);
2685}2681}
26862682
2687pub fn writeDataInCode(self: *MachO) !void {2683pub fn writeDataInCode(self: *MachO) link.File.FlushError!void {
2688 const tracy = trace(@src());2684 const tracy = trace(@src());
2689 defer tracy.end();2685 defer tracy.end();
2690 const gpa = self.base.comp.gpa;2686 const gpa = self.base.comp.gpa;
2691 const cmd = self.data_in_code_cmd;2687 const cmd = self.data_in_code_cmd;
2692 var buffer = try std.ArrayList(u8).initCapacity(gpa, self.data_in_code.size());2688
2693 defer buffer.deinit();2689 var bw: Writer = .fixed(try gpa.alloc(u8, self.data_in_code.size()));
2694 try self.data_in_code.write(self, buffer.writer());2690 defer gpa.free(bw.buffer);
2695 try self.pwriteAll(buffer.items, cmd.dataoff);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);
2696}2695}
26972696
2698fn writeIndsymtab(self: *MachO) !void {2697fn writeIndsymtab(self: *MachO) !void {
2699 const tracy = trace(@src());2698 const tracy = trace(@src());
2700 defer tracy.end();2699 defer tracy.end();
2700
2701 const gpa = self.base.comp.gpa;2701 const gpa = self.base.comp.gpa;
2702 const cmd = self.dysymtab_cmd;2702 const cmd = self.dysymtab_cmd;
2703 const needed_size = cmd.nindirectsyms * @sizeOf(u32);2703
2704 var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size);2704 var bw: Writer = .fixed(try gpa.alloc(u8, @sizeOf(u32) * cmd.nindirectsyms));
2705 defer buffer.deinit();2705 defer gpa.free(bw.buffer);
2706 try self.indsymtab.write(self, buffer.writer());2706
2707 try self.pwriteAll(buffer.items, cmd.indirectsymoff);2707 try self.indsymtab.write(self, &bw);
2708 assert(bw.end == bw.buffer.len);
2709 try self.pwriteAll(bw.buffer, cmd.indirectsymoff);
2708}2710}
27092711
2710pub fn writeSymtabToFile(self: *MachO) !void {2712pub fn writeSymtabToFile(self: *MachO) !void {
...@@ -2814,15 +2816,12 @@ fn calcSymtabSize(self: *MachO) !void {...@@ -2814,15 +2816,12 @@ fn calcSymtabSize(self: *MachO) !void {
2814 }2816 }
2815}2817}
28162818
2817fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {2819fn writeLoadCommands(self: *MachO) Writer.Error!struct { usize, usize, u64 } {
2818 const comp = self.base.comp;2820 const comp = self.base.comp;
2819 const gpa = comp.gpa;2821 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);2823 var bw: Writer = .fixed(try gpa.alloc(u8, try load_commands.calcLoadCommandsSize(self, false)));
2825 const writer = stream.writer();2824 defer gpa.free(bw.buffer);
28262825
2827 var ncmds: usize = 0;2826 var ncmds: usize = 0;
28282827
...@@ -2831,26 +2830,26 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2831,26 +2830,26 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2831 const slice = self.sections.slice();2830 const slice = self.sections.slice();
2832 var sect_id: usize = 0;2831 var sect_id: usize = 0;
2833 for (self.segments.items) |seg| {2832 for (self.segments.items) |seg| {
2834 try writer.writeStruct(seg);2833 try bw.writeStruct(seg);
2835 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {2834 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
2836 try writer.writeStruct(header);2835 try bw.writeStruct(header);
2837 }2836 }
2838 sect_id += seg.nsects;2837 sect_id += seg.nsects;
2839 }2838 }
2840 ncmds += self.segments.items.len;2839 ncmds += self.segments.items.len;
2841 }2840 }
28422841
2843 try writer.writeStruct(self.dyld_info_cmd);2842 try bw.writeStruct(self.dyld_info_cmd);
2844 ncmds += 1;2843 ncmds += 1;
2845 try writer.writeStruct(self.function_starts_cmd);2844 try bw.writeStruct(self.function_starts_cmd);
2846 ncmds += 1;2845 ncmds += 1;
2847 try writer.writeStruct(self.data_in_code_cmd);2846 try bw.writeStruct(self.data_in_code_cmd);
2848 ncmds += 1;2847 ncmds += 1;
2849 try writer.writeStruct(self.symtab_cmd);2848 try bw.writeStruct(self.symtab_cmd);
2850 ncmds += 1;2849 ncmds += 1;
2851 try writer.writeStruct(self.dysymtab_cmd);2850 try bw.writeStruct(self.dysymtab_cmd);
2852 ncmds += 1;2851 ncmds += 1;
2853 try load_commands.writeDylinkerLC(writer);2852 try load_commands.writeDylinkerLC(&bw);
2854 ncmds += 1;2853 ncmds += 1;
28552854
2856 if (self.getInternalObject()) |obj| {2855 if (self.getInternalObject()) |obj| {
...@@ -2861,7 +2860,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2861,7 +2860,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2861 02860 0
2862 else2861 else
2863 @as(u32, @intCast(sym.getAddress(.{ .stubs = true }, self) - seg.vmaddr));2862 @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{
2865 .entryoff = entryoff,2864 .entryoff = entryoff,
2866 .stacksize = self.base.stack_size,2865 .stacksize = self.base.stack_size,
2867 });2866 });
...@@ -2870,35 +2869,35 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2870,35 +2869,35 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2870 }2869 }
28712870
2872 if (self.base.isDynLib()) {2871 if (self.base.isDynLib()) {
2873 try load_commands.writeDylibIdLC(self, writer);2872 try load_commands.writeDylibIdLC(self, &bw);
2874 ncmds += 1;2873 ncmds += 1;
2875 }2874 }
28762875
2877 for (self.rpath_list) |rpath| {2876 for (self.rpath_list) |rpath| {
2878 try load_commands.writeRpathLC(rpath, writer);2877 try load_commands.writeRpathLC(&bw, rpath);
2879 ncmds += 1;2878 ncmds += 1;
2880 }2879 }
2881 if (comp.config.any_sanitize_thread) {2880 if (comp.config.any_sanitize_thread) {
2882 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);2881 const path = try comp.tsan_lib.?.full_object_path.toString(gpa);
2883 defer gpa.free(path);2882 defer gpa.free(path);
2884 const rpath = std.fs.path.dirname(path) orelse ".";2883 const rpath = std.fs.path.dirname(path) orelse ".";
2885 try load_commands.writeRpathLC(rpath, writer);2884 try load_commands.writeRpathLC(&bw, rpath);
2886 ncmds += 1;2885 ncmds += 1;
2887 }2886 }
28882887
2889 try writer.writeStruct(macho.source_version_command{ .version = 0 });2888 try bw.writeStruct(macho.source_version_command{ .version = 0 });
2890 ncmds += 1;2889 ncmds += 1;
28912890
2892 if (self.platform.isBuildVersionCompatible()) {2891 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);
2894 ncmds += 1;2893 ncmds += 1;
2895 } else {2894 } else {
2896 try load_commands.writeVersionMinLC(self.platform, self.sdk_version, writer);2895 try load_commands.writeVersionMinLC(&bw, self.platform, self.sdk_version);
2897 ncmds += 1;2896 ncmds += 1;
2898 }2897 }
28992898
2900 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + stream.pos;2899 const uuid_cmd_offset = @sizeOf(macho.mach_header_64) + bw.count;
2901 try writer.writeStruct(self.uuid_cmd);2900 try bw.writeStruct(self.uuid_cmd);
2902 ncmds += 1;2901 ncmds += 1;
29032902
2904 for (self.dylibs.items) |index| {2903 for (self.dylibs.items) |index| {
...@@ -2916,20 +2915,19 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2916,20 +2915,19 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2916 .timestamp = dylib_id.timestamp,2915 .timestamp = dylib_id.timestamp,
2917 .current_version = dylib_id.current_version,2916 .current_version = dylib_id.current_version,
2918 .compatibility_version = dylib_id.compatibility_version,2917 .compatibility_version = dylib_id.compatibility_version,
2919 }, writer);2918 }, &bw);
2920 ncmds += 1;2919 ncmds += 1;
2921 }2920 }
29222921
2923 if (self.requiresCodeSig()) {2922 if (self.requiresCodeSig()) {
2924 try writer.writeStruct(self.codesig_cmd);2923 try bw.writeStruct(self.codesig_cmd);
2925 ncmds += 1;2924 ncmds += 1;
2926 }2925 }
29272926
2928 assert(stream.pos == needed_size);2927 assert(bw.end == bw.buffer.len);
29292928 try self.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
2930 try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
29312929
2932 return .{ ncmds, buffer.len, uuid_cmd_offset };2930 return .{ ncmds, bw.end, uuid_cmd_offset };
2933}2931}
29342932
2935fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {2933fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void {
...@@ -3012,27 +3010,27 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {...@@ -3012,27 +3010,27 @@ pub fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
3012}3010}
30133011
3014pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {3012pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void {
3013 const gpa = self.base.comp.gpa;
3015 const seg = self.getTextSegment();3014 const seg = self.getTextSegment();
3016 const offset = self.codesig_cmd.dataoff;3015 const offset = self.codesig_cmd.dataoff;
30173016
3018 var buffer = std.ArrayList(u8).init(self.base.comp.gpa);3017 var bw: Writer = .fixed(try gpa.alloc(u8, code_sig.size()));
3019 defer buffer.deinit();3018 defer gpa.free(bw.buffer);
3020 try buffer.ensureTotalCapacityPrecise(code_sig.size());
3021 try code_sig.writeAdhocSignature(self, .{3019 try code_sig.writeAdhocSignature(self, .{
3022 .file = self.base.file.?,3020 .file = self.base.file.?,
3023 .exec_seg_base = seg.fileoff,3021 .exec_seg_base = seg.fileoff,
3024 .exec_seg_limit = seg.filesize,3022 .exec_seg_limit = seg.filesize,
3025 .file_size = offset,3023 .file_size = offset,
3026 .dylib = self.base.isDynLib(),3024 .dylib = self.base.isDynLib(),
3027 }, buffer.writer());3025 }, &bw);
3028 assert(buffer.items.len == code_sig.size());
30293026
3030 log.debug("writing code signature from 0x{x} to 0x{x}", .{3027 log.debug("writing code signature from 0x{x} to 0x{x}", .{
3031 offset,3028 offset,
3032 offset + buffer.items.len,3029 offset + bw.end,
3033 });3030 });
30343031
3035 try self.pwriteAll(buffer.items, offset);3032 assert(bw.end == bw.buffer.len);
3033 try self.pwriteAll(bw.buffer, offset);
3036}3034}
30373035
3038pub fn updateFunc(3036pub fn updateFunc(
...@@ -3341,7 +3339,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3341,7 +3339,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3341 }3339 }
33423340
3343 const appendSect = struct {3341 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 {
3345 const sect = &macho_file.sections.items(.header)[sect_id];3343 const sect = &macho_file.sections.items(.header)[sect_id];
3346 const seg = macho_file.segments.items[seg_id];3344 const seg = macho_file.segments.items[seg_id];
3347 sect.addr = seg.vmaddr;3345 sect.addr = seg.vmaddr;
...@@ -3600,7 +3598,7 @@ inline fn requiresThunks(self: MachO) bool {...@@ -3600,7 +3598,7 @@ inline fn requiresThunks(self: MachO) bool {
3600}3598}
36013599
3602pub fn isZigSegment(self: MachO, seg_id: u8) bool {3600pub fn isZigSegment(self: MachO, seg_id: u8) bool {
3603 inline for (&[_]?u8{3601 inline for (&[_]?u4{
3604 self.zig_text_seg_index,3602 self.zig_text_seg_index,
3605 self.zig_const_seg_index,3603 self.zig_const_seg_index,
3606 self.zig_data_seg_index,3604 self.zig_data_seg_index,
...@@ -3648,9 +3646,9 @@ pub fn addSegment(self: *MachO, name: []const u8, opts: struct {...@@ -3648,9 +3646,9 @@ pub fn addSegment(self: *MachO, name: []const u8, opts: struct {
3648 fileoff: u64 = 0,3646 fileoff: u64 = 0,
3649 filesize: u64 = 0,3647 filesize: u64 = 0,
3650 prot: macho.vm_prot_t = macho.PROT.NONE,3648 prot: macho.vm_prot_t = macho.PROT.NONE,
3651}) error{OutOfMemory}!u8 {3649}) error{OutOfMemory}!u4 {
3652 const gpa = self.base.comp.gpa;3650 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);
3654 try self.segments.append(gpa, .{3652 try self.segments.append(gpa, .{
3655 .segname = makeStaticString(name),3653 .segname = makeStaticString(name),
3656 .vmaddr = opts.vmaddr,3654 .vmaddr = opts.vmaddr,
...@@ -3700,9 +3698,9 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 {...@@ -3700,9 +3698,9 @@ pub fn makeStaticString(bytes: []const u8) [16]u8 {
3700 return buf;3698 return buf;
3701}3699}
37023700
3703pub fn getSegmentByName(self: MachO, segname: []const u8) ?u8 {3701pub fn getSegmentByName(self: MachO, segname: []const u8) ?u4 {
3704 for (self.segments.items, 0..) |seg, i| {3702 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);
3706 } else return null;3704 } else return null;
3707}3705}
37083706
...@@ -3791,7 +3789,7 @@ pub fn reportParseError2(...@@ -3791,7 +3789,7 @@ pub fn reportParseError2(
3791 const diags = &self.base.comp.link_diags;3789 const diags = &self.base.comp.link_diags;
3792 var err = try diags.addErrorWithNotes(1);3790 var err = try diags.addErrorWithNotes(1);
3793 try err.addMsg(format, args);3791 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()});
3795}3793}
37963794
3797fn reportMissingDependencyError(3795fn reportMissingDependencyError(
...@@ -3806,7 +3804,7 @@ fn reportMissingDependencyError(...@@ -3806,7 +3804,7 @@ fn reportMissingDependencyError(
3806 var err = try diags.addErrorWithNotes(2 + checked_paths.len);3804 var err = try diags.addErrorWithNotes(2 + checked_paths.len);
3807 try err.addMsg(format, args);3805 try err.addMsg(format, args);
3808 err.addNote("while resolving {s}", .{path});3806 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()});
3810 for (checked_paths) |p| {3808 for (checked_paths) |p| {
3811 err.addNote("tried {s}", .{p});3809 err.addNote("tried {s}", .{p});
3812 }3810 }
...@@ -3823,7 +3821,7 @@ fn reportDependencyError(...@@ -3823,7 +3821,7 @@ fn reportDependencyError(
3823 var err = try diags.addErrorWithNotes(2);3821 var err = try diags.addErrorWithNotes(2);
3824 try err.addMsg(format, args);3822 try err.addMsg(format, args);
3825 err.addNote("while parsing {s}", .{path});3823 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()});
3827}3825}
38283826
3829fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {3827fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
...@@ -3853,12 +3851,12 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {...@@ -3853,12 +3851,12 @@ fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void {
38533851
3854 var err = try diags.addErrorWithNotes(nnotes + 1);3852 var err = try diags.addErrorWithNotes(nnotes + 1);
3855 try err.addMsg("duplicate symbol definition: {s}", .{sym.getName(self)});3853 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
3858 var inote: usize = 0;3856 var inote: usize = 0;
3859 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {3857 while (inote < @min(notes.items.len, max_notes)) : (inote += 1) {
3860 const file = self.getFile(notes.items[inote]).?;3858 const file = self.getFile(notes.items[inote]).?;
3861 err.addNote("defined by {}", .{file.fmtPath()});3859 err.addNote("defined by {f}", .{file.fmtPath()});
3862 }3860 }
38633861
3864 if (notes.items.len > max_notes) {3862 if (notes.items.len > max_notes) {
...@@ -3900,35 +3898,28 @@ pub fn ptraceDetach(self: *MachO, pid: std.posix.pid_t) !void {...@@ -3900,35 +3898,28 @@ pub fn ptraceDetach(self: *MachO, pid: std.posix.pid_t) !void {
3900 self.hot_state.mach_task = null;3898 self.hot_state.mach_task = null;
3901}3899}
39023900
3903pub fn dumpState(self: *MachO) std.fmt.Formatter(fmtDumpState) {3901pub fn dumpState(self: *MachO) std.fmt.Formatter(*MachO, fmtDumpState) {
3904 return .{ .data = self };3902 return .{ .data = self };
3905}3903}
39063904
3907fn fmtDumpState(3905fn fmtDumpState(self: *MachO, w: *Writer) Writer.Error!void {
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;
3915 if (self.getZigObject()) |zo| {3906 if (self.getZigObject()) |zo| {
3916 try writer.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename });3907 try w.print("zig_object({d}) : {s}\n", .{ zo.index, zo.basename });
3917 try writer.print("{}{}\n", .{3908 try w.print("{f}{f}\n", .{
3918 zo.fmtAtoms(self),3909 zo.fmtAtoms(self),
3919 zo.fmtSymtab(self),3910 zo.fmtSymtab(self),
3920 });3911 });
3921 }3912 }
3922 for (self.objects.items) |index| {3913 for (self.objects.items) |index| {
3923 const object = self.getFile(index).?.object;3914 const object = self.getFile(index).?.object;
3924 try writer.print("object({d}) : {} : has_debug({})", .{3915 try w.print("object({d}) : {f} : has_debug({})", .{
3925 index,3916 index,
3926 object.fmtPath(),3917 object.fmtPath(),
3927 object.hasDebugInfo(),3918 object.hasDebugInfo(),
3928 });3919 });
3929 if (!object.alive) try writer.writeAll(" : ([*])");3920 if (!object.alive) try w.writeAll(" : ([*])");
3930 try writer.writeByte('\n');3921 try w.writeByte('\n');
3931 try writer.print("{}{}{}{}{}\n", .{3922 try w.print("{f}{f}{f}{f}{f}\n", .{
3932 object.fmtAtoms(self),3923 object.fmtAtoms(self),
3933 object.fmtCies(self),3924 object.fmtCies(self),
3934 object.fmtFdes(self),3925 object.fmtFdes(self),
...@@ -3938,48 +3929,41 @@ fn fmtDumpState(...@@ -3938,48 +3929,41 @@ fn fmtDumpState(
3938 }3929 }
3939 for (self.dylibs.items) |index| {3930 for (self.dylibs.items) |index| {
3940 const dylib = self.getFile(index).?.dylib;3931 const dylib = self.getFile(index).?.dylib;
3941 try writer.print("dylib({d}) : {} : needed({}) : weak({})", .{3932 try w.print("dylib({d}) : {f} : needed({}) : weak({})", .{
3942 index,3933 index,
3943 @as(Path, dylib.path),3934 @as(Path, dylib.path),
3944 dylib.needed,3935 dylib.needed,
3945 dylib.weak,3936 dylib.weak,
3946 });3937 });
3947 if (!dylib.isAlive(self)) try writer.writeAll(" : ([*])");3938 if (!dylib.isAlive(self)) try w.writeAll(" : ([*])");
3948 try writer.writeByte('\n');3939 try w.writeByte('\n');
3949 try writer.print("{}\n", .{dylib.fmtSymtab(self)});3940 try w.print("{f}\n", .{dylib.fmtSymtab(self)});
3950 }3941 }
3951 if (self.getInternalObject()) |internal| {3942 if (self.getInternalObject()) |internal| {
3952 try writer.print("internal({d}) : internal\n", .{internal.index});3943 try w.print("internal({d}) : internal\n", .{internal.index});
3953 try writer.print("{}{}\n", .{ internal.fmtAtoms(self), internal.fmtSymtab(self) });3944 try w.print("{f}{f}\n", .{ internal.fmtAtoms(self), internal.fmtSymtab(self) });
3954 }3945 }
3955 try writer.writeAll("thunks\n");3946 try w.writeAll("thunks\n");
3956 for (self.thunks.items, 0..) |thunk, index| {3947 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) });
3958 }3949 }
3959 try writer.print("stubs\n{}\n", .{self.stubs.fmt(self)});3950 try w.print("stubs\n{f}\n", .{self.stubs.fmt(self)});
3960 try writer.print("objc_stubs\n{}\n", .{self.objc_stubs.fmt(self)});3951 try w.print("objc_stubs\n{f}\n", .{self.objc_stubs.fmt(self)});
3961 try writer.print("got\n{}\n", .{self.got.fmt(self)});3952 try w.print("got\n{f}\n", .{self.got.fmt(self)});
3962 try writer.print("tlv_ptr\n{}\n", .{self.tlv_ptr.fmt(self)});3953 try w.print("tlv_ptr\n{f}\n", .{self.tlv_ptr.fmt(self)});
3963 try writer.writeByte('\n');3954 try w.writeByte('\n');
3964 try writer.print("sections\n{}\n", .{self.fmtSections()});3955 try w.print("sections\n{f}\n", .{self.fmtSections()});
3965 try writer.print("segments\n{}\n", .{self.fmtSegments()});3956 try w.print("segments\n{f}\n", .{self.fmtSegments()});
3966}3957}
39673958
3968fn fmtSections(self: *MachO) std.fmt.Formatter(formatSections) {3959fn fmtSections(self: *MachO) std.fmt.Formatter(*MachO, formatSections) {
3969 return .{ .data = self };3960 return .{ .data = self };
3970}3961}
39713962
3972fn formatSections(3963fn formatSections(self: *MachO, w: *Writer) Writer.Error!void {
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;
3980 const slice = self.sections.slice();3964 const slice = self.sections.slice();
3981 for (slice.items(.header), slice.items(.segment_id), 0..) |header, seg_id, i| {3965 for (slice.items(.header), slice.items(.segment_id), 0..) |header, seg_id, i| {
3982 try writer.print(3966 try w.print(
3983 "sect({d}) : seg({d}) : {s},{s} : @{x} ({x}) : align({x}) : size({x}) : relocs({x};{d})\n",3967 "sect({d}) : seg({d}) : {s},{s} : @{x} ({x}) : align({x}) : size({x}) : relocs({x};{d})\n",
3984 .{3968 .{
3985 i, seg_id, header.segName(), header.sectName(), header.addr, header.offset,3969 i, seg_id, header.segName(), header.sectName(), header.addr, header.offset,
...@@ -3989,38 +3973,24 @@ fn formatSections(...@@ -3989,38 +3973,24 @@ fn formatSections(
3989 }3973 }
3990}3974}
39913975
3992fn fmtSegments(self: *MachO) std.fmt.Formatter(formatSegments) {3976fn fmtSegments(self: *MachO) std.fmt.Formatter(*MachO, formatSegments) {
3993 return .{ .data = self };3977 return .{ .data = self };
3994}3978}
39953979
3996fn formatSegments(3980fn formatSegments(self: *MachO, w: *Writer) Writer.Error!void {
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;
4004 for (self.segments.items, 0..) |seg, i| {3981 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", .{
4006 i, seg.segName(), seg.vmaddr, seg.vmaddr + seg.vmsize,3983 i, seg.segName(), seg.vmaddr, seg.vmaddr + seg.vmsize,
4007 seg.fileoff, seg.fileoff + seg.filesize,3984 seg.fileoff, seg.fileoff + seg.filesize,
4008 });3985 });
4009 }3986 }
4010}3987}
40113988
4012pub fn fmtSectType(tt: u8) std.fmt.Formatter(formatSectType) {3989pub fn fmtSectType(tt: u8) std.fmt.Formatter(u8, formatSectType) {
4013 return .{ .data = tt };3990 return .{ .data = tt };
4014}3991}
40153992
4016fn formatSectType(3993fn formatSectType(tt: u8, w: *Writer) Writer.Error!void {
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;
4024 const name = switch (tt) {3994 const name = switch (tt) {
4025 macho.S_REGULAR => "REGULAR",3995 macho.S_REGULAR => "REGULAR",
4026 macho.S_ZEROFILL => "ZEROFILL",3996 macho.S_ZEROFILL => "ZEROFILL",
...@@ -4044,9 +4014,9 @@ fn formatSectType(...@@ -4044,9 +4014,9 @@ fn formatSectType(
4044 macho.S_THREAD_LOCAL_VARIABLE_POINTERS => "THREAD_LOCAL_VARIABLE_POINTERS",4014 macho.S_THREAD_LOCAL_VARIABLE_POINTERS => "THREAD_LOCAL_VARIABLE_POINTERS",
4045 macho.S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => "THREAD_LOCAL_INIT_FUNCTION_POINTERS",4015 macho.S_THREAD_LOCAL_INIT_FUNCTION_POINTERS => "THREAD_LOCAL_INIT_FUNCTION_POINTERS",
4046 macho.S_INIT_FUNC_OFFSETS => "INIT_FUNC_OFFSETS",4016 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}),
4048 };4018 };
4049 try writer.print("{s}", .{name});4019 try w.print("{s}", .{name});
4050}4020}
40514021
4052const is_hot_update_compatible = switch (builtin.target.os.tag) {4022const is_hot_update_compatible = switch (builtin.target.os.tag) {
...@@ -4058,7 +4028,7 @@ const default_entry_symbol_name = "_main";...@@ -4058,7 +4028,7 @@ const default_entry_symbol_name = "_main";
40584028
4059const Section = struct {4029const Section = struct {
4060 header: macho.section_64,4030 header: macho.section_64,
4061 segment_id: u8,4031 segment_id: u4,
4062 atoms: std.ArrayListUnmanaged(Ref) = .empty,4032 atoms: std.ArrayListUnmanaged(Ref) = .empty,
4063 free_list: std.ArrayListUnmanaged(Atom.Index) = .empty,4033 free_list: std.ArrayListUnmanaged(Atom.Index) = .empty,
4064 last_atom_index: Atom.Index = 0,4034 last_atom_index: Atom.Index = 0,
...@@ -4279,28 +4249,21 @@ pub const Platform = struct {...@@ -4279,28 +4249,21 @@ pub const Platform = struct {
4279 return false;4249 return false;
4280 }4250 }
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) {
4283 return .{ .data = .{ .platform = plat, .cpu_arch = cpu_arch } };4253 return .{ .data = .{ .platform = plat, .cpu_arch = cpu_arch } };
4284 }4254 }
42854255
4286 const FmtCtx = struct {4256 const Format = struct {
4287 platform: Platform,4257 platform: Platform,
4288 cpu_arch: std.Target.Cpu.Arch,4258 cpu_arch: std.Target.Cpu.Arch,
4289 };
42904259
4291 pub fn formatTarget(4260 pub fn target(f: Format, w: *Writer) Writer.Error!void {
4292 ctx: FmtCtx,4261 try w.print("{s}-{s}", .{ @tagName(f.cpu_arch), @tagName(f.platform.os_tag) });
4293 comptime unused_fmt_string: []const u8,4262 if (f.platform.abi != .none) {
4294 options: std.fmt.FormatOptions,4263 try w.print("-{s}", .{@tagName(f.platform.abi)});
4295 writer: anytype,4264 }
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)});
4302 }4265 }
4303 }4266 };
43044267
4305 /// Caller owns the memory.4268 /// Caller owns the memory.
4306 pub fn allocPrintTarget(plat: Platform, gpa: Allocator, cpu_arch: std.Target.Cpu.Arch) error{OutOfMemory}![]u8 {4269 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...@@ -4390,7 +4353,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
4390// The file/property is also available with vendored libc.4353// The file/property is also available with vendored libc.
4391fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {4354fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {
4392 const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" });4355 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)));
4394 const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});4357 const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});
4395 if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;4358 if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;
4396 return error.SdkVersionFailure;4359 return error.SdkVersionFailure;
...@@ -4406,7 +4369,7 @@ fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion {...@@ -4406,7 +4369,7 @@ fn parseSdkVersion(raw: []const u8) ?std.SemanticVersion {
4406 };4369 };
44074370
4408 const parseNext = struct {4371 const parseNext = struct {
4409 fn parseNext(it: anytype) ?u16 {4372 fn parseNext(it: *std.mem.SplitIterator(u8, .any)) ?u16 {
4410 const nn = it.next() orelse return null;4373 const nn = it.next() orelse return null;
4411 return std.fmt.parseInt(u16, nn, 10) catch null;4374 return std.fmt.parseInt(u16, nn, 10) catch null;
4412 }4375 }
...@@ -4507,15 +4470,9 @@ pub const Ref = struct {...@@ -4507,15 +4470,9 @@ pub const Ref = struct {
4507 };4470 };
4508 }4471 }
45094472
4510 pub fn format(4473 pub fn format(ref: Ref, bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void {
4511 ref: Ref,4474 comptime assert(unused_fmt_string.len == 0);
4512 comptime unused_fmt_string: []const u8,4475 try bw.print("%{d} in file({d})", .{ ref.index, ref.file });
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 });
4519 }4476 }
4520};4477};
45214478
...@@ -5315,7 +5272,7 @@ fn createThunks(macho_file: *MachO, sect_id: u8) !void {...@@ -5315,7 +5272,7 @@ fn createThunks(macho_file: *MachO, sect_id: u8) !void {
5315 try scanThunkRelocs(thunk_index, gpa, atoms[start..i], macho_file);5272 try scanThunkRelocs(thunk_index, gpa, atoms[start..i], macho_file);
5316 thunk.value = advanceSection(header, thunk.size(), .@"4");5273 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) });
5319 }5276 }
5320}5277}
53215278
...@@ -5360,8 +5317,11 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {...@@ -5360,8 +5317,11 @@ fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool {
5360pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void {5317pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void {
5361 const comp = macho_file.base.comp;5318 const comp = macho_file.base.comp;
5362 const diags = &comp.link_diags;5319 const diags = &comp.link_diags;
5363 macho_file.base.file.?.pwriteAll(bytes, offset) catch |err| {5320 var fw = macho_file.base.file.?.writer();
5364 return diags.fail("failed to write: {s}", .{@errorName(err)});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.?)}),
5365 };5325 };
5366}5326}
53675327
...@@ -5414,6 +5374,7 @@ const macho = std.macho;...@@ -5414,6 +5374,7 @@ const macho = std.macho;
5414const math = std.math;5374const math = std.math;
5415const mem = std.mem;5375const mem = std.mem;
5416const meta = std.meta;5376const meta = std.meta;
5377const Writer = std.io.Writer;
54175378
5418const aarch64 = @import("../arch/aarch64/bits.zig");5379const aarch64 = @import("../arch/aarch64/bits.zig");
5419const bind = @import("MachO/dyld_info/bind.zig");5380const 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...@@ -71,53 +71,29 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File
71 .mtime = hdr.date() catch 0,71 .mtime = hdr.date() catch 0,
72 };72 };
7373
74 log.debug("extracting object '{}' from archive '{}'", .{ object.path, path });74 log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path });
7575
76 try self.objects.append(gpa, object);76 try self.objects.append(gpa, object);
77 }77 }
78}78}
7979
80pub fn writeHeader(80pub fn writeHeader(
81 bw: *Writer,
81 object_name: []const u8,82 object_name: []const u8,
82 object_size: usize,83 object_size: usize,
83 format: Format,84 format: Format,
84 writer: anytype,85) Writer.Error!void {
85) !void {86 var hdr: ar_hdr = undefined;
86 var hdr: ar_hdr = .{87 @memset(mem.asBytes(&hdr), ' ');
87 .ar_name = undefined,88 inline for (@typeInfo(ar_hdr).@"struct".fields) |field| @field(hdr, field.name)[0] = '0';
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 }
100 @memcpy(&hdr.ar_fmag, ARFMAG);89 @memcpy(&hdr.ar_fmag, ARFMAG);
101
102 const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format));90 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;
103 const total_object_size = object_size + object_name_len;92 const total_object_size = object_size + object_name_len;
10493 _ = std.fmt.bufPrint(&hdr.ar_size, "{d}", .{total_object_size}) catch unreachable;
105 {94 try bw.writeStruct(hdr);
106 var stream = std.io.fixedBufferStream(&hdr.ar_name);95 try bw.writeAll(object_name);
107 stream.writer().print("#1/{d}", .{object_name_len}) catch unreachable;96 try bw.splatByteAll(0, object_name_len - object_name.len);
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 }
121}97}
12298
123// Archive files start with the ARMAG identifying string. Then follows a99// Archive files start with the ARMAG identifying string. Then follows a
...@@ -201,12 +177,12 @@ pub const ArSymtab = struct {...@@ -201,12 +177,12 @@ pub const ArSymtab = struct {
201 return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);177 return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
202 }178 }
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 {
205 const ptr_width = ptrWidth(format);181 const ptr_width = ptrWidth(format);
206 // Header182 // Header
207 try writeHeader(SYMDEF, ar.size(format), format, writer);183 try writeHeader(bw, SYMDEF, ar.size(format), format);
208 // Symtab size184 // 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);
210 // Symtab entries186 // Symtab entries
211 for (ar.entries.items) |entry| {187 for (ar.entries.items) |entry| {
212 const file_off = switch (macho_file.getFile(entry.file).?) {188 const file_off = switch (macho_file.getFile(entry.file).?) {
...@@ -215,47 +191,37 @@ pub const ArSymtab = struct {...@@ -215,47 +191,37 @@ pub const ArSymtab = struct {
215 else => unreachable,191 else => unreachable,
216 };192 };
217 // Name offset193 // Name offset
218 try writeInt(format, entry.off, writer);194 try writeInt(bw, format, entry.off);
219 // File offset195 // File offset
220 try writeInt(format, file_off, writer);196 try writeInt(bw, format, file_off);
221 }197 }
222 // Strtab size198 // Strtab size
223 const strtab_size = mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);199 const strtab_size = mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width);
224 const padding = strtab_size - ar.strtab.buffer.items.len;200 try writeInt(bw, format, strtab_size);
225 try writeInt(format, strtab_size, writer);
226 // Strtab201 // Strtab
227 try writer.writeAll(ar.strtab.buffer.items);202 try bw.writeAll(ar.strtab.buffer.items);
228 if (padding > 0) {203 try bw.splatByteAll(0, strtab_size - ar.strtab.buffer.items.len);
229 try writer.writeByteNTimes(0, padding);
230 }
231 }204 }
232205
233 const FormatContext = struct {206 const PrintFormat = struct {
234 ar: ArSymtab,207 ar: ArSymtab,
235 macho_file: *MachO,208 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 }
236 };219 };
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) {
239 return .{ .data = .{ .ar = ar, .macho_file = macho_file } };222 return .{ .data = .{ .ar = ar, .macho_file = macho_file } };
240 }223 }
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
259 const Entry = struct {225 const Entry = struct {
260 /// Symbol name offset226 /// Symbol name offset
261 off: u32,227 off: u32,
...@@ -282,10 +248,10 @@ pub fn ptrWidth(format: Format) usize {...@@ -282,10 +248,10 @@ pub fn ptrWidth(format: Format) usize {
282 };248 };
283}249}
284250
285pub fn writeInt(format: Format, value: u64, writer: anytype) !void {251pub fn writeInt(bw: *Writer, format: Format, value: u64) Writer.Error!void {
286 switch (format) {252 switch (format) {
287 .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),253 .p32 => try bw.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little),
288 .p64 => try writer.writeInt(u64, value, .little),254 .p64 => try bw.writeInt(u64, value, .little),
289 }255 }
290}256}
291257
...@@ -304,8 +270,9 @@ const log = std.log.scoped(.link);...@@ -304,8 +270,9 @@ const log = std.log.scoped(.link);
304const macho = std.macho;270const macho = std.macho;
305const mem = std.mem;271const mem = std.mem;
306const std = @import("std");272const std = @import("std");
307const Allocator = mem.Allocator;273const Allocator = std.mem.Allocator;
308const Path = std.Build.Cache.Path;274const Path = std.Build.Cache.Path;
275const Writer = std.io.Writer;
309276
310const Archive = @This();277const Archive = @This();
311const File = @import("file.zig").File;278const 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 {...@@ -580,8 +580,9 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
580580
581 relocs_log.debug("{x}: {s}", .{ self.value, name });581 relocs_log.debug("{x}: {s}", .{ self.value, name });
582582
583 var bw: Writer = .fixed(buffer);
584
583 var has_error = false;585 var has_error = false;
584 var stream = std.io.fixedBufferStream(buffer);
585 var i: usize = 0;586 var i: usize = 0;
586 while (i < relocs.len) : (i += 1) {587 while (i < relocs.len) : (i += 1) {
587 const rel = relocs[i];588 const rel = relocs[i];
...@@ -592,30 +593,28 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {...@@ -592,30 +593,28 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void {
592 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;593 if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue;
593 }594 }
594595
595 try stream.seekTo(rel_offset);596 bw.end = std.math.cast(usize, rel_offset) orelse return error.Overflow;
596 self.resolveRelocInner(rel, subtractor, buffer, macho_file, stream.writer()) catch |err| {597 self.resolveRelocInner(rel, subtractor, buffer, macho_file, &bw) catch |err| switch (err) {
597 switch (err) {598 error.RelaxFail => {
598 error.RelaxFail => {599 const target = switch (rel.tag) {
599 const target = switch (rel.tag) {600 .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),
600 .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file),601 .local => rel.getTargetAtom(self, macho_file).getName(macho_file),
601 .local => rel.getTargetAtom(self, macho_file).getName(macho_file),602 };
602 };603 try macho_file.reportParseError2(
603 try macho_file.reportParseError2(604 file.getIndex(),
604 file.getIndex(),605 "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {f}, target {s}",
605 "{s}: 0x{x}: 0x{x}: failed to relax relocation: type {}, target {s}",606 .{
606 .{607 name,
607 name,608 self.getAddress(macho_file),
608 self.getAddress(macho_file),609 rel.offset,
609 rel.offset,610 rel.fmtPretty(macho_file.getTarget().cpu.arch),
610 rel.fmtPretty(macho_file.getTarget().cpu.arch),611 target,
611 target,612 },
612 },613 );
613 );614 has_error = true;
614 has_error = true;615 },
615 },616 error.RelaxFailUnexpectedInstruction => has_error = true,
616 error.RelaxFailUnexpectedInstruction => has_error = true,617 else => |e| return e,
617 else => |e| return e,
618 }
619 };618 };
620 }619 }
621620
...@@ -638,8 +637,8 @@ fn resolveRelocInner(...@@ -638,8 +637,8 @@ fn resolveRelocInner(
638 subtractor: ?Relocation,637 subtractor: ?Relocation,
639 code: []u8,638 code: []u8,
640 macho_file: *MachO,639 macho_file: *MachO,
641 writer: anytype,640 bw: *Writer,
642) ResolveError!void {641) Writer.Error!void {
643 const t = &macho_file.base.comp.root_mod.resolved_target.result;642 const t = &macho_file.base.comp.root_mod.resolved_target.result;
644 const cpu_arch = t.cpu.arch;643 const cpu_arch = t.cpu.arch;
645 const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;644 const rel_offset = math.cast(usize, rel.offset - self.off) orelse return error.Overflow;
...@@ -653,7 +652,7 @@ fn resolveRelocInner(...@@ -653,7 +652,7 @@ fn resolveRelocInner(
653 const divExact = struct {652 const divExact = struct {
654 fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {653 fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {
655 return math.divExact(u12, num, den) catch {654 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}", .{
657 atom.getName(ctx),656 atom.getName(ctx),
658 r.fmtPretty(ctx.getTarget().cpu.arch),657 r.fmtPretty(ctx.getTarget().cpu.arch),
659 r.offset,658 r.offset,
...@@ -664,14 +663,14 @@ fn resolveRelocInner(...@@ -664,14 +663,14 @@ fn resolveRelocInner(
664 }.divExact;663 }.divExact;
665664
666 switch (rel.tag) {665 switch (rel.tag) {
667 .local => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] atom({d})", .{666 .local => relocs_log.debug(" {x}<+{d}>: {f}: [=> {x}] atom({d})", .{
668 P,667 P,
669 rel_offset,668 rel_offset,
670 rel.fmtPretty(cpu_arch),669 rel.fmtPretty(cpu_arch),
671 S + A - SUB,670 S + A - SUB,
672 rel.getTargetAtom(self, macho_file).atom_index,671 rel.getTargetAtom(self, macho_file).atom_index,
673 }),672 }),
674 .@"extern" => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] G({x}) ({s})", .{673 .@"extern" => relocs_log.debug(" {x}<+{d}>: {f}: [=> {x}] G({x}) ({s})", .{
675 P,674 P,
676 rel_offset,675 rel_offset,
677 rel.fmtPretty(cpu_arch),676 rel.fmtPretty(cpu_arch),
...@@ -690,14 +689,14 @@ fn resolveRelocInner(...@@ -690,14 +689,14 @@ fn resolveRelocInner(
690 if (rel.tag == .@"extern") {689 if (rel.tag == .@"extern") {
691 const sym = rel.getTargetSymbol(self, macho_file);690 const sym = rel.getTargetSymbol(self, macho_file);
692 if (sym.isTlvInit(macho_file)) {691 if (sym.isTlvInit(macho_file)) {
693 try writer.writeInt(u64, @intCast(S - TLS), .little);692 try bw.writeInt(u64, @intCast(S - TLS), .little);
694 return;693 return;
695 }694 }
696 if (sym.flags.import) return;695 if (sym.flags.import) return;
697 }696 }
698 try writer.writeInt(u64, @bitCast(S + A - SUB), .little);697 try bw.writeInt(u64, @bitCast(S + A - SUB), .little);
699 } else if (rel.meta.length == 2) {698 } 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);
701 } else unreachable;700 } else unreachable;
702 },701 },
703702
...@@ -705,7 +704,7 @@ fn resolveRelocInner(...@@ -705,7 +704,7 @@ fn resolveRelocInner(
705 assert(rel.tag == .@"extern");704 assert(rel.tag == .@"extern");
706 assert(rel.meta.length == 2);705 assert(rel.meta.length == 2);
707 assert(rel.meta.pcrel);706 assert(rel.meta.pcrel);
708 try writer.writeInt(i32, @intCast(G + A - P), .little);707 try bw.writeInt(i32, @intCast(G + A - P), .little);
709 },708 },
710709
711 .branch => {710 .branch => {
...@@ -714,7 +713,7 @@ fn resolveRelocInner(...@@ -714,7 +713,7 @@ fn resolveRelocInner(
714 assert(rel.tag == .@"extern");713 assert(rel.tag == .@"extern");
715714
716 switch (cpu_arch) {715 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),
718 .aarch64 => {717 .aarch64 => {
719 const disp: i28 = math.cast(i28, S + A - P) orelse blk: {718 const disp: i28 = math.cast(i28, S + A - P) orelse blk: {
720 const thunk = self.getThunk(macho_file);719 const thunk = self.getThunk(macho_file);
...@@ -732,10 +731,10 @@ fn resolveRelocInner(...@@ -732,10 +731,10 @@ fn resolveRelocInner(
732 assert(rel.meta.length == 2);731 assert(rel.meta.length == 2);
733 assert(rel.meta.pcrel);732 assert(rel.meta.pcrel);
734 if (rel.getTargetSymbol(self, macho_file).getSectionFlags().has_got) {733 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);
736 } else {735 } else {
737 try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file);736 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);
739 }738 }
740 },739 },
741740
...@@ -746,17 +745,17 @@ fn resolveRelocInner(...@@ -746,17 +745,17 @@ fn resolveRelocInner(
746 const sym = rel.getTargetSymbol(self, macho_file);745 const sym = rel.getTargetSymbol(self, macho_file);
747 if (sym.getSectionFlags().tlv_ptr) {746 if (sym.getSectionFlags().tlv_ptr) {
748 const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file));747 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);
750 } else {749 } else {
751 try x86_64.relaxTlv(code[rel_offset - 3 ..], t);750 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);
753 }752 }
754 },753 },
755754
756 .signed, .signed1, .signed2, .signed4 => {755 .signed, .signed1, .signed2, .signed4 => {
757 assert(rel.meta.length == 2);756 assert(rel.meta.length == 2);
758 assert(rel.meta.pcrel);757 assert(rel.meta.pcrel);
759 try writer.writeInt(i32, @intCast(S + A - P), .little);758 try bw.writeInt(i32, @intCast(S + A - P), .little);
760 },759 },
761760
762 .page,761 .page,
...@@ -808,7 +807,7 @@ fn resolveRelocInner(...@@ -808,7 +807,7 @@ fn resolveRelocInner(
808 2 => try divExact(self, rel, @truncate(target), 4, macho_file),807 2 => try divExact(self, rel, @truncate(target), 4, macho_file),
809 3 => try divExact(self, rel, @truncate(target), 8, macho_file),808 3 => try divExact(self, rel, @truncate(target), 8, macho_file),
810 };809 };
811 try writer.writeInt(u32, inst.toU32(), .little);810 try bw.writeInt(u32, inst.toU32(), .little);
812 }811 }
813 },812 },
814813
...@@ -886,7 +885,7 @@ fn resolveRelocInner(...@@ -886,7 +885,7 @@ fn resolveRelocInner(
886 .sf = @as(u1, @truncate(reg_info.size)),885 .sf = @as(u1, @truncate(reg_info.size)),
887 },886 },
888 };887 };
889 try writer.writeInt(u32, inst.toU32(), .little);888 try bw.writeInt(u32, inst.toU32(), .little);
890 },889 },
891 }890 }
892}891}
...@@ -900,19 +899,19 @@ const x86_64 = struct {...@@ -900,19 +899,19 @@ const x86_64 = struct {
900 switch (old_inst.encoding.mnemonic) {899 switch (old_inst.encoding.mnemonic) {
901 .mov => {900 .mov => {
902 const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops, t) catch return error.RelaxFail;901 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 });
904 encode(&.{inst}, code) catch return error.RelaxFail;903 encode(&.{inst}, code) catch return error.RelaxFail;
905 },904 },
906 else => |x| {905 else => |x| {
907 var err = try diags.addErrorWithNotes(2);906 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}", .{
909 self.getName(macho_file),908 self.getName(macho_file),
910 self.getAddress(macho_file),909 self.getAddress(macho_file),
911 rel.offset,910 rel.offset,
912 rel.fmtPretty(.x86_64),911 rel.fmtPretty(.x86_64),
913 });912 });
914 err.addNote("expected .mov instruction but found .{s}", .{@tagName(x)});913 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()});
916 return error.RelaxFailUnexpectedInstruction;915 return error.RelaxFailUnexpectedInstruction;
917 },916 },
918 }917 }
...@@ -924,7 +923,7 @@ const x86_64 = struct {...@@ -924,7 +923,7 @@ const x86_64 = struct {
924 switch (old_inst.encoding.mnemonic) {923 switch (old_inst.encoding.mnemonic) {
925 .mov => {924 .mov => {
926 const inst = Instruction.new(old_inst.prefix, .lea, &old_inst.ops, t) catch return error.RelaxFail;925 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 });
928 encode(&.{inst}, code) catch return error.RelaxFail;927 encode(&.{inst}, code) catch return error.RelaxFail;
929 },928 },
930 else => return error.RelaxFail,929 else => return error.RelaxFail,
...@@ -938,11 +937,8 @@ const x86_64 = struct {...@@ -938,11 +937,8 @@ const x86_64 = struct {
938 }937 }
939938
940 fn encode(insts: []const Instruction, code: []u8) !void {939 fn encode(insts: []const Instruction, code: []u8) !void {
941 var stream = std.io.fixedBufferStream(code);940 var bw: Writer = .fixed(code);
942 const writer = stream.writer();941 for (insts) |inst| try inst.encode(&bw, .{});
943 for (insts) |inst| {
944 try inst.encode(writer, .{});
945 }
946 }942 }
947943
948 const bits = @import("../../arch/x86_64/bits.zig");944 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...@@ -1003,7 +999,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
1003 }999 }
10041000
1005 switch (rel.tag) {1001 switch (rel.tag) {
1006 .local => relocs_log.debug(" {}: [{x} => {d}({s},{s})] + {x}", .{1002 .local => relocs_log.debug(" {f}: [{x} => {d}({s},{s})] + {x}", .{
1007 rel.fmtPretty(cpu_arch),1003 rel.fmtPretty(cpu_arch),
1008 r_address,1004 r_address,
1009 r_symbolnum,1005 r_symbolnum,
...@@ -1011,7 +1007,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r...@@ -1011,7 +1007,7 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
1011 macho_file.sections.items(.header)[r_symbolnum - 1].sectName(),1007 macho_file.sections.items(.header)[r_symbolnum - 1].sectName(),
1012 addend,1008 addend,
1013 }),1009 }),
1014 .@"extern" => relocs_log.debug(" {}: [{x} => {d}({s})] + {x}", .{1010 .@"extern" => relocs_log.debug(" {f}: [{x} => {d}({s})] + {x}", .{
1015 rel.fmtPretty(cpu_arch),1011 rel.fmtPretty(cpu_arch),
1016 r_address,1012 r_address,
1017 r_symbolnum,1013 r_symbolnum,
...@@ -1117,60 +1113,40 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r...@@ -1117,60 +1113,40 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
1117 assert(i == buffer.len);1113 assert(i == buffer.len);
1118}1114}
11191115
1120pub fn format(1116pub fn fmt(atom: Atom, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
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) {
1134 return .{ .data = .{1117 return .{ .data = .{
1135 .atom = atom,1118 .atom = atom,
1136 .macho_file = macho_file,1119 .macho_file = macho_file,
1137 } };1120 } };
1138}1121}
11391122
1140const FormatContext = struct {1123const Format = struct {
1141 atom: Atom,1124 atom: Atom,
1142 macho_file: *MachO,1125 macho_file: *MachO,
1143};
11441126
1145fn format2(1127 fn print(f: Format, w: *Writer) Writer.Error!void {
1146 ctx: FormatContext,1128 const atom = f.atom;
1147 comptime unused_fmt_string: []const u8,1129 const macho_file = f.macho_file;
1148 options: std.fmt.FormatOptions,1130 const file = atom.getFile(macho_file);
1149 writer: anytype,1131 try w.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{
1150) !void {1132 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),
1151 _ = options;1133 atom.out_n_sect, atom.alignment, atom.size,
1152 _ = unused_fmt_string;1134 atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk,
1153 const atom = ctx.atom;1135 });
1154 const macho_file = ctx.macho_file;1136 if (!atom.isAlive()) try w.writeAll(" : [*]");
1155 const file = atom.getFile(macho_file);1137 if (atom.getUnwindRecords(macho_file).len > 0) {
1156 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d}) : thunk({d})", .{1138 try w.writeAll(" : unwind{ ");
1157 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),1139 const extra = atom.getExtra(macho_file);
1158 atom.out_n_sect, atom.alignment, atom.size,1140 for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| {
1159 atom.getRelocs(macho_file).len, atom.getExtra(macho_file).thunk,1141 const rec = file.object.getUnwindRecord(index);
1160 });1142 try w.print("{d}", .{index});
1161 if (!atom.isAlive()) try writer.writeAll(" : [*]");1143 if (!rec.alive) try w.writeAll("([*])");
1162 if (atom.getUnwindRecords(macho_file).len > 0) {1144 if (i < extra.unwind_index + extra.unwind_count - 1) try w.writeAll(", ");
1163 try writer.writeAll(" : unwind{ ");1145 }
1164 const extra = atom.getExtra(macho_file);1146 try w.writeAll(" }");
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(", ");
1170 }1147 }
1171 try writer.writeAll(" }");
1172 }1148 }
1173}1149};
11741150
1175pub const Index = u32;1151pub const Index = u32;
11761152
...@@ -1205,19 +1181,20 @@ pub const Extra = struct {...@@ -1205,19 +1181,20 @@ pub const Extra = struct {
12051181
1206pub const Alignment = @import("../../InternPool.zig").Alignment;1182pub const Alignment = @import("../../InternPool.zig").Alignment;
12071183
1208const aarch64 = @import("../aarch64.zig");1184const std = @import("std");
1209const assert = std.debug.assert;1185const assert = std.debug.assert;
1210const macho = std.macho;1186const macho = std.macho;
1211const math = std.math;1187const math = std.math;
1212const mem = std.mem;1188const mem = std.mem;
1213const log = std.log.scoped(.link);1189const log = std.log.scoped(.link);
1214const relocs_log = std.log.scoped(.link_relocs);1190const relocs_log = std.log.scoped(.link_relocs);
1215const std = @import("std");1191const Writer = std.io.Writer;
1216const trace = @import("../../tracy.zig").trace;
1217
1218const Allocator = mem.Allocator;1192const Allocator = mem.Allocator;
1219const Atom = @This();
1220const AtomicBool = std.atomic.Value(bool);1193const AtomicBool = std.atomic.Value(bool);
1194
1195const aarch64 = @import("../aarch64.zig");
1196const trace = @import("../../tracy.zig").trace;
1197const Atom = @This();
1221const File = @import("file.zig").File;1198const File = @import("file.zig").File;
1222const MachO = @import("../MachO.zig");1199const MachO = @import("../MachO.zig");
1223const Object = @import("Object.zig");1200const Object = @import("Object.zig");
src/link/MachO/CodeSignature.zig+11-9
...@@ -247,7 +247,7 @@ pub fn deinit(self: *CodeSignature, allocator: Allocator) void {...@@ -247,7 +247,7 @@ pub fn deinit(self: *CodeSignature, allocator: Allocator) void {
247pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void {247pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void {
248 const file = try fs.cwd().openFile(path, .{});248 const file = try fs.cwd().openFile(path, .{});
249 defer file.close();249 defer file.close();
250 const inner = try file.readToEndAlloc(allocator, std.math.maxInt(u32));250 const inner = try file.readToEndAlloc(allocator, .unlimited);
251 self.entitlements = .{ .inner = inner };251 self.entitlements = .{ .inner = inner };
252}252}
253253
...@@ -304,10 +304,11 @@ pub fn writeAdhocSignature(...@@ -304,10 +304,11 @@ pub fn writeAdhocSignature(
304 var hash: [hash_size]u8 = undefined;304 var hash: [hash_size]u8 = undefined;
305305
306 if (self.requirements) |*req| {306 if (self.requirements) |*req| {
307 var buf = std.ArrayList(u8).init(allocator);307 var aw: std.io.Writer.Allocating = .init(allocator);
308 defer buf.deinit();308 defer aw.deinit();
309 try req.write(buf.writer());309
310 Sha256.hash(buf.items, &hash, .{});310 try req.write(&aw.writer);
311 Sha256.hash(aw.getWritten(), &hash, .{});
311 self.code_directory.addSpecialHash(req.slotType(), hash);312 self.code_directory.addSpecialHash(req.slotType(), hash);
312313
313 try blobs.append(.{ .requirements = req });314 try blobs.append(.{ .requirements = req });
...@@ -316,10 +317,11 @@ pub fn writeAdhocSignature(...@@ -316,10 +317,11 @@ pub fn writeAdhocSignature(
316 }317 }
317318
318 if (self.entitlements) |*ents| {319 if (self.entitlements) |*ents| {
319 var buf = std.ArrayList(u8).init(allocator);320 var aw: std.io.Writer.Allocating = .init(allocator);
320 defer buf.deinit();321 defer aw.deinit();
321 try ents.write(buf.writer());322
322 Sha256.hash(buf.items, &hash, .{});323 try ents.write(&aw.writer);
324 Sha256.hash(aw.getWritten(), &hash, .{});
323 self.code_directory.addSpecialHash(ents.slotType(), hash);325 self.code_directory.addSpecialHash(ents.slotType(), hash);
324326
325 try blobs.append(.{ .entitlements = ents });327 try blobs.append(.{ .entitlements = ents });
src/link/MachO/DebugSymbols.zig+12-16
...@@ -269,18 +269,14 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {...@@ -269,18 +269,14 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
269269
270fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } {270fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } {
271 const gpa = self.allocator;271 const gpa = self.allocator;
272 const needed_size = load_commands.calcLoadCommandsSizeDsym(macho_file, self);272 var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeDsym(macho_file, self)));
273 const buffer = try gpa.alloc(u8, needed_size);273 defer gpa.free(bw.buffer);
274 defer gpa.free(buffer);
275
276 var stream = std.io.fixedBufferStream(buffer);
277 const writer = stream.writer();
278274
279 var ncmds: usize = 0;275 var ncmds: usize = 0;
280276
281 // UUID comes first presumably to speed up lookup by the consumer like lldb.277 // UUID comes first presumably to speed up lookup by the consumer like lldb.
282 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);278 @memcpy(&self.uuid_cmd.uuid, &macho_file.uuid_cmd.uuid);
283 try writer.writeStruct(self.uuid_cmd);279 try bw.writeStruct(self.uuid_cmd);
284 ncmds += 1;280 ncmds += 1;
285281
286 // Segment and section load commands282 // Segment and section load commands
...@@ -293,11 +289,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -293,11 +289,11 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
293 var out_seg = seg;289 var out_seg = seg;
294 out_seg.fileoff = 0;290 out_seg.fileoff = 0;
295 out_seg.filesize = 0;291 out_seg.filesize = 0;
296 try writer.writeStruct(out_seg);292 try bw.writeStruct(out_seg);
297 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {293 for (slice.items(.header)[sect_id..][0..seg.nsects]) |header| {
298 var out_header = header;294 var out_header = header;
299 out_header.offset = 0;295 out_header.offset = 0;
300 try writer.writeStruct(out_header);296 try bw.writeStruct(out_header);
301 }297 }
302 sect_id += seg.nsects;298 sect_id += seg.nsects;
303 }299 }
...@@ -306,23 +302,22 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u...@@ -306,23 +302,22 @@ fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, u
306 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.302 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
307 sect_id = 0;303 sect_id = 0;
308 for (self.segments.items) |seg| {304 for (self.segments.items) |seg| {
309 try writer.writeStruct(seg);305 try bw.writeStruct(seg);
310 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {306 for (self.sections.items[sect_id..][0..seg.nsects]) |header| {
311 try writer.writeStruct(header);307 try bw.writeStruct(header);
312 }308 }
313 sect_id += seg.nsects;309 sect_id += seg.nsects;
314 }310 }
315 ncmds += self.segments.items.len;311 ncmds += self.segments.items.len;
316 }312 }
317313
318 try writer.writeStruct(self.symtab_cmd);314 try bw.writeStruct(self.symtab_cmd);
319 ncmds += 1;315 ncmds += 1;
320316
321 assert(stream.pos == needed_size);317 assert(bw.end == bw.buffer.len);
322318 try self.file.?.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
323 try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
324319
325 return .{ ncmds, buffer.len };320 return .{ ncmds, bw.end };
326}321}
327322
328fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {323fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
...@@ -460,6 +455,7 @@ const math = std.math;...@@ -460,6 +455,7 @@ const math = std.math;
460const mem = std.mem;455const mem = std.mem;
461const padToIdeal = MachO.padToIdeal;456const padToIdeal = MachO.padToIdeal;
462const trace = @import("../../tracy.zig").trace;457const trace = @import("../../tracy.zig").trace;
458const Writer = std.io.Writer;
463459
464const Allocator = mem.Allocator;460const Allocator = mem.Allocator;
465const MachO = @import("../MachO.zig");461const MachO = @import("../MachO.zig");
src/link/MachO/Dwarf.zig+18-30
...@@ -81,7 +81,7 @@ pub const InfoReader = struct {...@@ -81,7 +81,7 @@ pub const InfoReader = struct {
81 .dwarf64 => 12,81 .dwarf64 => 12,
82 } + cuh_length;82 } + cuh_length;
83 while (p.pos < end_pos) {83 while (p.pos < end_pos) {
84 const di_code = try p.readUleb128(u64);84 const di_code = try p.readLeb128(u64);
85 if (di_code == 0) return error.UnexpectedEndOfFile;85 if (di_code == 0) return error.UnexpectedEndOfFile;
86 if (di_code == code) return;86 if (di_code == code) return;
8787
...@@ -174,14 +174,14 @@ pub const InfoReader = struct {...@@ -174,14 +174,14 @@ pub const InfoReader = struct {
174 dw.FORM.block1 => try p.readByte(),174 dw.FORM.block1 => try p.readByte(),
175 dw.FORM.block2 => try p.readInt(u16),175 dw.FORM.block2 => try p.readInt(u16),
176 dw.FORM.block4 => try p.readInt(u32),176 dw.FORM.block4 => try p.readInt(u32),
177 dw.FORM.block => try p.readUleb128(u64),177 dw.FORM.block => try p.readLeb128(u64),
178 else => unreachable,178 else => unreachable,
179 };179 };
180 return p.readNBytes(len);180 return p.readNBytes(len);
181 }181 }
182182
183 pub fn readExprLoc(p: *InfoReader) ![]const u8 {183 pub fn readExprLoc(p: *InfoReader) ![]const u8 {
184 const len: u64 = try p.readUleb128(u64);184 const len: u64 = try p.readLeb128(u64);
185 return p.readNBytes(len);185 return p.readNBytes(len);
186 }186 }
187187
...@@ -191,8 +191,8 @@ pub const InfoReader = struct {...@@ -191,8 +191,8 @@ pub const InfoReader = struct {
191 dw.FORM.data2, dw.FORM.ref2 => try p.readInt(u16),191 dw.FORM.data2, dw.FORM.ref2 => try p.readInt(u16),
192 dw.FORM.data4, dw.FORM.ref4 => try p.readInt(u32),192 dw.FORM.data4, dw.FORM.ref4 => try p.readInt(u32),
193 dw.FORM.data8, dw.FORM.ref8, dw.FORM.ref_sig8 => try p.readInt(u64),193 dw.FORM.data8, dw.FORM.ref8, dw.FORM.ref_sig8 => try p.readInt(u64),
194 dw.FORM.udata, dw.FORM.ref_udata => try p.readUleb128(u64),194 dw.FORM.udata, dw.FORM.ref_udata => try p.readLeb128(u64),
195 dw.FORM.sdata => @bitCast(try p.readIleb128(i64)),195 dw.FORM.sdata => @bitCast(try p.readLeb128(i64)),
196 else => return error.UnhandledConstantForm,196 else => return error.UnhandledConstantForm,
197 };197 };
198 }198 }
...@@ -203,7 +203,7 @@ pub const InfoReader = struct {...@@ -203,7 +203,7 @@ pub const InfoReader = struct {
203 dw.FORM.strx2, dw.FORM.addrx2 => try p.readInt(u16),203 dw.FORM.strx2, dw.FORM.addrx2 => try p.readInt(u16),
204 dw.FORM.strx3, dw.FORM.addrx3 => error.UnhandledForm,204 dw.FORM.strx3, dw.FORM.addrx3 => error.UnhandledForm,
205 dw.FORM.strx4, dw.FORM.addrx4 => try p.readInt(u32),205 dw.FORM.strx4, dw.FORM.addrx4 => try p.readInt(u32),
206 dw.FORM.strx, dw.FORM.addrx => try p.readUleb128(u64),206 dw.FORM.strx, dw.FORM.addrx => try p.readLeb128(u64),
207 else => return error.UnhandledIndexForm,207 else => return error.UnhandledIndexForm,
208 };208 };
209 }209 }
...@@ -272,20 +272,10 @@ pub const InfoReader = struct {...@@ -272,20 +272,10 @@ pub const InfoReader = struct {
272 };272 };
273 }273 }
274274
275 pub fn readUleb128(p: *InfoReader, comptime Type: type) !Type {275 pub fn readLeb128(p: *InfoReader, comptime Type: type) !Type {
276 var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);276 var r: std.io.Reader = .fixed(p.bytes()[p.pos..]);
277 var creader = std.io.countingReader(stream.reader());277 defer p.pos += r.seek;
278 const value: Type = try leb.readUleb128(Type, creader.reader());278 return r.takeLeb128(Type);
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;
289 }279 }
290280
291 pub fn seekTo(p: *InfoReader, off: u64) !void {281 pub fn seekTo(p: *InfoReader, off: u64) !void {
...@@ -307,10 +297,10 @@ pub const AbbrevReader = struct {...@@ -307,10 +297,10 @@ pub const AbbrevReader = struct {
307297
308 pub fn readDecl(p: *AbbrevReader) !?AbbrevDecl {298 pub fn readDecl(p: *AbbrevReader) !?AbbrevDecl {
309 const pos = p.pos;299 const pos = p.pos;
310 const code = try p.readUleb128(Code);300 const code = try p.readLeb128(Code);
311 if (code == 0) return null;301 if (code == 0) return null;
312302
313 const tag = try p.readUleb128(Tag);303 const tag = try p.readLeb128(Tag);
314 const has_children = (try p.readByte()) > 0;304 const has_children = (try p.readByte()) > 0;
315 return .{305 return .{
316 .code = code,306 .code = code,
...@@ -323,8 +313,8 @@ pub const AbbrevReader = struct {...@@ -323,8 +313,8 @@ pub const AbbrevReader = struct {
323313
324 pub fn readAttr(p: *AbbrevReader) !?AbbrevAttr {314 pub fn readAttr(p: *AbbrevReader) !?AbbrevAttr {
325 const pos = p.pos;315 const pos = p.pos;
326 const at = try p.readUleb128(At);316 const at = try p.readLeb128(At);
327 const form = try p.readUleb128(Form);317 const form = try p.readLeb128(Form);
328 return if (at == 0 and form == 0) null else .{318 return if (at == 0 and form == 0) null else .{
329 .at = at,319 .at = at,
330 .form = form,320 .form = form,
...@@ -339,12 +329,10 @@ pub const AbbrevReader = struct {...@@ -339,12 +329,10 @@ pub const AbbrevReader = struct {
339 return p.bytes()[p.pos];329 return p.bytes()[p.pos];
340 }330 }
341331
342 pub fn readUleb128(p: *AbbrevReader, comptime Type: type) !Type {332 pub fn readLeb128(p: *AbbrevReader, comptime Type: type) !Type {
343 var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);333 var r: std.io.Reader = .fixed(p.bytes()[p.pos..]);
344 var creader = std.io.countingReader(stream.reader());334 defer p.pos += r.seek;
345 const value: Type = try leb.readUleb128(Type, creader.reader());335 return r.takeLeb128(Type);
346 p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
347 return value;
348 }336 }
349337
350 pub fn seekTo(p: *AbbrevReader, off: u64) !void {338 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 {...@@ -61,7 +61,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
61 const file = macho_file.getFileHandle(self.file_handle);61 const file = macho_file.getFileHandle(self.file_handle);
62 const offset = self.offset;62 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
66 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;66 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
67 {67 {
...@@ -140,7 +140,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {...@@ -140,7 +140,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
140140
141 if (self.platform) |platform| {141 if (self.platform) |platform| {
142 if (!macho_file.platform.eqlTarget(platform)) {142 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}", .{
144 platform.fmtTarget(macho_file.getTarget().cpu.arch),144 platform.fmtTarget(macho_file.getTarget().cpu.arch),
145 });145 });
146 return error.InvalidTarget;146 return error.InvalidTarget;
...@@ -148,7 +148,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {...@@ -148,7 +148,7 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
148 // TODO: this can cause the CI to fail so I'm commenting this check out so that148 // TODO: this can cause the CI to fail so I'm commenting this check out so that
149 // I can work out the rest of the changes first149 // I can work out the rest of the changes first
150 // if (macho_file.platform.version.order(platform.version) == .lt) {150 // 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}", .{
152 // macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),152 // macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),
153 // macho_file.platform.version,153 // macho_file.platform.version,
154 // platform.version,154 // platform.version,
...@@ -158,46 +158,6 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {...@@ -158,46 +158,6 @@ fn parseBinary(self: *Dylib, macho_file: *MachO) !void {
158 }158 }
159}159}
160160
161const TrieIterator = struct {
162 data: []const u8,
163 pos: usize = 0,
164
165 fn getStream(it: *TrieIterator) std.io.FixedBufferStream([]const u8) {
166 return std.io.fixedBufferStream(it.data[it.pos..]);
167 }
168
169 fn readUleb128(it: *TrieIterator) !u64 {
170 var stream = it.getStream();
171 var creader = std.io.countingReader(stream.reader());
172 const reader = creader.reader();
173 const value = try std.leb.readUleb128(u64, reader);
174 it.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
175 return value;
176 }
177
178 fn readString(it: *TrieIterator) ![:0]const u8 {
179 var stream = it.getStream();
180 const reader = stream.reader();
181
182 var count: usize = 0;
183 while (true) : (count += 1) {
184 const byte = try reader.readByte();
185 if (byte == 0) break;
186 }
187
188 const str = @as([*:0]const u8, @ptrCast(it.data.ptr + it.pos))[0..count :0];
189 it.pos += count + 1;
190 return str;
191 }
192
193 fn readByte(it: *TrieIterator) !u8 {
194 var stream = it.getStream();
195 const value = try stream.reader().readByte();
196 it.pos += 1;
197 return value;
198 }
199};
200
201pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void {161pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void {
202 try self.exports.append(allocator, .{162 try self.exports.append(allocator, .{
203 .name = try self.addString(allocator, name),163 .name = try self.addString(allocator, name),
...@@ -207,16 +167,16 @@ pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Ex...@@ -207,16 +167,16 @@ pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Ex
207167
208fn parseTrieNode(168fn parseTrieNode(
209 self: *Dylib,169 self: *Dylib,
210 it: *TrieIterator,170 br: *std.io.Reader,
211 allocator: Allocator,171 allocator: Allocator,
212 arena: Allocator,172 arena: Allocator,
213 prefix: []const u8,173 prefix: []const u8,
214) !void {174) !void {
215 const tracy = trace(@src());175 const tracy = trace(@src());
216 defer tracy.end();176 defer tracy.end();
217 const size = try it.readUleb128();177 const size = try br.takeLeb128(u64);
218 if (size > 0) {178 if (size > 0) {
219 const flags = try it.readUleb128();179 const flags = try br.takeLeb128(u8);
220 const kind = flags & macho.EXPORT_SYMBOL_FLAGS_KIND_MASK;180 const kind = flags & macho.EXPORT_SYMBOL_FLAGS_KIND_MASK;
221 const out_flags = Export.Flags{181 const out_flags = Export.Flags{
222 .abs = kind == macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE,182 .abs = kind == macho.EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE,
...@@ -224,29 +184,28 @@ fn parseTrieNode(...@@ -224,29 +184,28 @@ fn parseTrieNode(
224 .weak = flags & macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION != 0,184 .weak = flags & macho.EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION != 0,
225 };185 };
226 if (flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT != 0) {186 if (flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT != 0) {
227 _ = try it.readUleb128(); // dylib ordinal187 _ = try br.takeLeb128(u64); // dylib ordinal
228 const name = try it.readString();188 const name = try br.takeSentinel(0);
229 try self.addExport(allocator, if (name.len > 0) name else prefix, out_flags);189 try self.addExport(allocator, if (name.len > 0) name else prefix, out_flags);
230 } else if (flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER != 0) {190 } else if (flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER != 0) {
231 _ = try it.readUleb128(); // stub offset191 _ = try br.takeLeb128(u64); // stub offset
232 _ = try it.readUleb128(); // resolver offset192 _ = try br.takeLeb128(u64); // resolver offset
233 try self.addExport(allocator, prefix, out_flags);193 try self.addExport(allocator, prefix, out_flags);
234 } else {194 } else {
235 _ = try it.readUleb128(); // VM offset195 _ = try br.takeLeb128(u64); // VM offset
236 try self.addExport(allocator, prefix, out_flags);196 try self.addExport(allocator, prefix, out_flags);
237 }197 }
238 }198 }
239199
240 const nedges = try it.readByte();200 const nedges = try br.takeByte();
241
242 for (0..nedges) |_| {201 for (0..nedges) |_| {
243 const label = try it.readString();202 const label = try br.takeSentinel(0);
244 const off = try it.readUleb128();203 const off = try br.takeLeb128(usize);
245 const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label });204 const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label });
246 const curr = it.pos;205 const seek = br.seek;
247 it.pos = math.cast(usize, off) orelse return error.Overflow;206 br.seek = off;
248 try self.parseTrieNode(it, allocator, arena, prefix_label);207 try self.parseTrieNode(br, allocator, arena, prefix_label);
249 it.pos = curr;208 br.seek = seek;
250 }209 }
251}210}
252211
...@@ -257,8 +216,8 @@ fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void {...@@ -257,8 +216,8 @@ fn parseTrie(self: *Dylib, data: []const u8, macho_file: *MachO) !void {
257 var arena = std.heap.ArenaAllocator.init(gpa);216 var arena = std.heap.ArenaAllocator.init(gpa);
258 defer arena.deinit();217 defer arena.deinit();
259218
260 var it: TrieIterator = .{ .data = data };219 var r: std.io.Reader = .fixed(data);
261 try self.parseTrieNode(&it, gpa, arena.allocator(), "");220 try self.parseTrieNode(&r, gpa, arena.allocator(), "");
262}221}
263222
264fn parseTbd(self: *Dylib, macho_file: *MachO) !void {223fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
...@@ -267,7 +226,7 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void {...@@ -267,7 +226,7 @@ fn parseTbd(self: *Dylib, macho_file: *MachO) !void {
267226
268 const gpa = macho_file.base.comp.gpa;227 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
272 const file = macho_file.getFileHandle(self.file_handle);231 const file = macho_file.getFileHandle(self.file_handle);
273 var lib_stub = LibStub.loadFromFile(gpa, file) catch |err| {232 var lib_stub = LibStub.loadFromFile(gpa, file) catch |err| {
...@@ -691,52 +650,32 @@ pub fn setSymbolExtra(self: *Dylib, index: u32, extra: Symbol.Extra) void {...@@ -691,52 +650,32 @@ pub fn setSymbolExtra(self: *Dylib, index: u32, extra: Symbol.Extra) void {
691 }650 }
692}651}
693652
694pub fn format(653pub fn fmtSymtab(self: *Dylib, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
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) {
708 return .{ .data = .{654 return .{ .data = .{
709 .dylib = self,655 .dylib = self,
710 .macho_file = macho_file,656 .macho_file = macho_file,
711 } };657 } };
712}658}
713659
714const FormatContext = struct {660const Format = struct {
715 dylib: *Dylib,661 dylib: *Dylib,
716 macho_file: *MachO,662 macho_file: *MachO,
717};
718663
719fn formatSymtab(664 fn symtab(f: Format, w: *Writer) Writer.Error!void {
720 ctx: FormatContext,665 const dylib = f.dylib;
721 comptime unused_fmt_string: []const u8,666 const macho_file = f.macho_file;
722 options: std.fmt.FormatOptions,667 try w.writeAll(" globals\n");
723 writer: anytype,668 for (dylib.symbols.items, 0..) |sym, i| {
724) !void {669 const ref = dylib.getSymbolRef(@intCast(i), macho_file);
725 _ = unused_fmt_string;670 if (ref.getFile(macho_file) == null) {
726 _ = options;671 // TODO any better way of handling this?
727 const dylib = ctx.dylib;672 try w.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
728 const macho_file = ctx.macho_file;673 } else {
729 try writer.writeAll(" globals\n");674 try w.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
730 for (dylib.symbols.items, 0..) |sym, i| {675 }
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)});
737 }676 }
738 }677 }
739}678};
740679
741pub const TargetMatcher = struct {680pub const TargetMatcher = struct {
742 allocator: Allocator,681 allocator: Allocator,
...@@ -948,19 +887,17 @@ const Export = struct {...@@ -948,19 +887,17 @@ const Export = struct {
948 };887 };
949};888};
950889
890const std = @import("std");
951const assert = std.debug.assert;891const assert = std.debug.assert;
952const fat = @import("fat.zig");
953const fs = std.fs;892const fs = std.fs;
954const fmt = std.fmt;893const fmt = std.fmt;
955const log = std.log.scoped(.link);894const log = std.log.scoped(.link);
956const macho = std.macho;895const macho = std.macho;
957const math = std.math;896const math = std.math;
958const mem = std.mem;897const mem = std.mem;
959const tapi = @import("../tapi.zig");
960const trace = @import("../../tracy.zig").trace;
961const std = @import("std");
962const Allocator = mem.Allocator;898const Allocator = mem.Allocator;
963const Path = std.Build.Cache.Path;899const Path = std.Build.Cache.Path;
900const Writer = std.io.Writer;
964901
965const Dylib = @This();902const Dylib = @This();
966const File = @import("file.zig").File;903const File = @import("file.zig").File;
...@@ -969,3 +906,6 @@ const LoadCommandIterator = macho.LoadCommandIterator;...@@ -969,3 +906,6 @@ const LoadCommandIterator = macho.LoadCommandIterator;
969const MachO = @import("../MachO.zig");906const MachO = @import("../MachO.zig");
970const Symbol = @import("Symbol.zig");907const Symbol = @import("Symbol.zig");
971const Tbd = tapi.Tbd;908const 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...@@ -261,7 +261,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
261261
262 sect.offset = @intCast(self.objc_methnames.items.len);262 sect.offset = @intCast(self.objc_methnames.items.len);
263 try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);263 try self.objc_methnames.ensureUnusedCapacity(gpa, methname.len + 1);
264 self.objc_methnames.writer(gpa).print("{s}\x00", .{methname}) catch unreachable;264 self.objc_methnames.print(gpa, "{s}\x00", .{methname}) catch unreachable;
265265
266 const name_str = try self.addString(gpa, "ltmp");266 const name_str = try self.addString(gpa, "ltmp");
267 const sym_index = try self.addSymbol(gpa);267 const sym_index = try self.addSymbol(gpa);
...@@ -836,62 +836,48 @@ fn needsObjcMsgsendSymbol(self: InternalObject) bool {...@@ -836,62 +836,48 @@ fn needsObjcMsgsendSymbol(self: InternalObject) bool {
836 return false;836 return false;
837}837}
838838
839const FormatContext = struct {839const Format = struct {
840 self: *InternalObject,840 self: *InternalObject,
841 macho_file: *MachO,841 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 }
842};865};
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) {
845 return .{ .data = .{868 return .{ .data = .{
846 .self = self,869 .self = self,
847 .macho_file = macho_file,870 .macho_file = macho_file,
848 } };871 } };
849}872}
850873
851fn formatAtoms(874pub fn fmtSymtab(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
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) {
867 return .{ .data = .{875 return .{ .data = .{
868 .self = self,876 .self = self,
869 .macho_file = macho_file,877 .macho_file = macho_file,
870 } };878 } };
871}879}
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
895const Section = struct {881const Section = struct {
896 header: macho.section_64,882 header: macho.section_64,
897 relocs: std.ArrayListUnmanaged(Relocation) = .empty,883 relocs: std.ArrayListUnmanaged(Relocation) = .empty,
...@@ -908,6 +894,7 @@ const macho = std.macho;...@@ -908,6 +894,7 @@ const macho = std.macho;
908const mem = std.mem;894const mem = std.mem;
909const std = @import("std");895const std = @import("std");
910const trace = @import("../../tracy.zig").trace;896const trace = @import("../../tracy.zig").trace;
897const Writer = std.io.Writer;
911898
912const Allocator = std.mem.Allocator;899const Allocator = std.mem.Allocator;
913const Atom = @import("Atom.zig");900const Atom = @import("Atom.zig");
src/link/MachO/Object.zig+101-164
...@@ -72,7 +72,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -72,7 +72,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
72 const tracy = trace(@src());72 const tracy = trace(@src());
73 defer tracy.end();73 defer tracy.end();
7474
75 log.debug("parsing {}", .{self.fmtPath()});75 log.debug("parsing {f}", .{self.fmtPath()});
7676
77 const gpa = macho_file.base.comp.gpa;77 const gpa = macho_file.base.comp.gpa;
78 const handle = macho_file.getFileHandle(self.file_handle);78 const handle = macho_file.getFileHandle(self.file_handle);
...@@ -239,7 +239,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -239,7 +239,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
239239
240 if (self.platform) |platform| {240 if (self.platform) |platform| {
241 if (!macho_file.platform.eqlTarget(platform)) {241 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}", .{
243 platform.fmtTarget(cpu_arch),243 platform.fmtTarget(cpu_arch),
244 });244 });
245 return error.InvalidTarget;245 return error.InvalidTarget;
...@@ -247,7 +247,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -247,7 +247,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
247 // TODO: this causes the CI to fail so I'm commenting this check out so that247 // TODO: this causes the CI to fail so I'm commenting this check out so that
248 // I can work out the rest of the changes first248 // I can work out the rest of the changes first
249 // if (macho_file.platform.version.order(platform.version) == .lt) {249 // 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}", .{
251 // macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),251 // macho_file.platform.fmtTarget(macho_file.getTarget().cpu.arch),
252 // macho_file.platform.version,252 // macho_file.platform.version,
253 // platform.version,253 // platform.version,
...@@ -308,7 +308,9 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {...@@ -308,7 +308,9 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {
308 } else nlists.len;308 } else nlists.len;
309309
310 if (nlist_start == nlist_end or nlists[nlist_start].nlist.n_value > sect.addr) {310 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);
312 defer allocator.free(name);314 defer allocator.free(name);
313 const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr;315 const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr;
314 const atom_index = try self.addAtom(allocator, .{316 const atom_index = try self.addAtom(allocator, .{
...@@ -364,7 +366,9 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {...@@ -364,7 +366,9 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void {
364 // which cannot be contained in any non-zero atom (since then this atom366 // which cannot be contained in any non-zero atom (since then this atom
365 // would exceed section boundaries). In order to facilitate this behaviour,367 // would exceed section boundaries). In order to facilitate this behaviour,
366 // we create a dummy zero-sized atom at section end (addr + size).368 // 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);
368 defer allocator.free(name);372 defer allocator.free(name);
369 const atom_index = try self.addAtom(allocator, .{373 const atom_index = try self.addAtom(allocator, .{
370 .name = try self.addString(allocator, name),374 .name = try self.addString(allocator, name),
...@@ -1065,7 +1069,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi...@@ -1065,7 +1069,7 @@ fn initEhFrameRecords(self: *Object, allocator: Allocator, sect_id: u8, file: Fi
1065 }1069 }
1066 }1070 }
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) };
1069 while (try it.next()) |rec| {1073 while (try it.next()) |rec| {
1070 switch (rec.tag) {1074 switch (rec.tag) {
1071 .cie => try self.cies.append(allocator, .{1075 .cie => try self.cies.append(allocator, .{
...@@ -1694,11 +1698,11 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {...@@ -1694,11 +1698,11 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
1694 };1698 };
1695}1699}
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 {
1698 // Header1702 // Header
1699 const size = try macho_file.cast(usize, self.output_ar_state.size);1703 const size = try macho_file.cast(usize, self.output_ar_state.size);
1700 const basename = std.fs.path.basename(self.path.sub_path);1704 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);
1702 // Data1706 // Data
1703 const file = macho_file.getFileHandle(self.file_handle);1707 const file = macho_file.getFileHandle(self.file_handle);
1704 // TODO try using copyRangeAll1708 // TODO try using copyRangeAll
...@@ -1707,7 +1711,7 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ...@@ -1707,7 +1711,7 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ
1707 defer gpa.free(data);1711 defer gpa.free(data);
1708 const amt = try file.preadAll(data, self.offset);1712 const amt = try file.preadAll(data, self.offset);
1709 if (amt != size) return error.InputOutput;1713 if (amt != size) return error.InputOutput;
1710 try writer.writeAll(data);1714 try bw.writeAll(data);
1711}1715}
17121716
1713pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {1717pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void {
...@@ -1861,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {...@@ -1861,7 +1865,7 @@ pub fn writeAtomsRelocatable(self: *Object, macho_file: *MachO) !void {
1861 }1865 }
1862 gpa.free(sections_data);1866 gpa.free(sections_data);
1863 }1867 }
1864 @memset(sections_data, &[0]u8{});1868 @memset(sections_data, &.{});
1865 const file = macho_file.getFileHandle(self.file_handle);1869 const file = macho_file.getFileHandle(self.file_handle);
18661870
1867 for (headers, 0..) |header, n_sect| {1871 for (headers, 0..) |header, n_sect| {
...@@ -2512,165 +2516,114 @@ pub fn readSectionData(self: Object, allocator: Allocator, file: File.Handle, n_...@@ -2512,165 +2516,114 @@ pub fn readSectionData(self: Object, allocator: Allocator, file: File.Handle, n_
2512 return data;2516 return data;
2513}2517}
25142518
2515pub fn format(2519const Format = struct {
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 {
2529 object: *Object,2520 object: *Object,
2530 macho_file: *MachO,2521 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 }
2531};2579};
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) {
2534 return .{ .data = .{2582 return .{ .data = .{
2535 .object = self,2583 .object = self,
2536 .macho_file = macho_file,2584 .macho_file = macho_file,
2537 } };2585 } };
2538}2586}
25392587
2540fn formatAtoms(2588pub fn fmtCies(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.cies) {
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) {
2558 return .{ .data = .{2589 return .{ .data = .{
2559 .object = self,2590 .object = self,
2560 .macho_file = macho_file,2591 .macho_file = macho_file,
2561 } };2592 } };
2562}2593}
25632594
2564fn formatCies(2595pub fn fmtFdes(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.fdes) {
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) {
2580 return .{ .data = .{2596 return .{ .data = .{
2581 .object = self,2597 .object = self,
2582 .macho_file = macho_file,2598 .macho_file = macho_file,
2583 } };2599 } };
2584}2600}
25852601
2586fn formatFdes(2602pub fn fmtUnwindRecords(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.unwindRecords) {
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) {
2602 return .{ .data = .{2603 return .{ .data = .{
2603 .object = self,2604 .object = self,
2604 .macho_file = macho_file,2605 .macho_file = macho_file,
2605 } };2606 } };
2606}2607}
26072608
2608fn formatUnwindRecords(2609pub fn fmtSymtab(self: *Object, macho_file: *MachO) std.fmt.Formatter(Format, Format.symtab) {
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) {
2625 return .{ .data = .{2610 return .{ .data = .{
2626 .object = self,2611 .object = self,
2627 .macho_file = macho_file,2612 .macho_file = macho_file,
2628 } };2613 } };
2629}2614}
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
2663pub fn fmtPath(self: Object) std.fmt.Formatter(Object, formatPath) {2616pub fn fmtPath(self: Object) std.fmt.Formatter(Object, formatPath) {
2664 return .{ .data = self };2617 return .{ .data = self };
2665}2618}
26662619
2667fn formatPath(object: Object, writer: *std.io.Writer) std.io.Writer.Error!void {2620fn formatPath(object: Object, w: *Writer) Writer.Error!void {
2668 if (object.in_archive) |ar| {2621 if (object.in_archive) |ar| {
2669 try writer.print("{f}({s})", .{2622 try w.print("{f}({s})", .{
2670 @as(Path, ar.path), object.path.basename(),2623 ar.path, object.path.basename(),
2671 });2624 });
2672 } else {2625 } else {
2673 try writer.print("{f}", .{@as(Path, object.path)});2626 try w.print("{f}", .{object.path});
2674 }2627 }
2675}2628}
26762629
...@@ -2724,43 +2677,26 @@ const StabFile = struct {...@@ -2724,43 +2677,26 @@ const StabFile = struct {
2724 return object.symbols.items[index];2677 return object.symbols.items[index];
2725 }2678 }
27262679
2727 pub fn format(2680 const Format = struct {
2728 stab: Stab,2681 stab: Stab,
2729 comptime unused_fmt_string: []const u8,2682 object: Object,
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 }
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) {
2743 return .{ .data = .{ stab, object } };2698 return .{ .data = .{ stab, object } };
2744 }2699 }
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 }
2764 };2700 };
2765};2701};
27662702
...@@ -3150,17 +3086,18 @@ const aarch64 = struct {...@@ -3150,17 +3086,18 @@ const aarch64 = struct {
3150 }3086 }
3151};3087};
31523088
3089const std = @import("std");
3153const assert = std.debug.assert;3090const assert = std.debug.assert;
3154const eh_frame = @import("eh_frame.zig");
3155const log = std.log.scoped(.link);3091const log = std.log.scoped(.link);
3156const macho = std.macho;3092const macho = std.macho;
3157const math = std.math;3093const math = std.math;
3158const mem = std.mem;3094const mem = std.mem;
3159const trace = @import("../../tracy.zig").trace;
3160const std = @import("std");
3161const Path = std.Build.Cache.Path;3095const 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;
3164const Archive = @import("Archive.zig");3101const Archive = @import("Archive.zig");
3165const Atom = @import("Atom.zig");3102const Atom = @import("Atom.zig");
3166const Cie = eh_frame.Cie;3103const 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 {...@@ -70,57 +70,51 @@ pub fn lessThan(ctx: void, lhs: Relocation, rhs: Relocation) bool {
70 return lhs.offset < rhs.offset;70 return lhs.offset < rhs.offset;
71}71}
7272
73const FormatCtx = struct { Relocation, std.Target.Cpu.Arch };73pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(Format, Format.pretty) {
74
75pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(formatPretty) {
76 return .{ .data = .{ rel, cpu_arch } };74 return .{ .data = .{ rel, cpu_arch } };
77}75}
7876
79fn formatPretty(77const Format = struct {
80 ctx: FormatCtx,78 relocation: Relocation,
81 comptime unused_fmt_string: []const u8,79 arch: std.Target.Cpu.Arch,
82 options: std.fmt.FormatOptions,80
83 writer: anytype,81 fn pretty(f: Format, w: *Writer) Writer.Error!void {
84) !void {82 try w.writeAll(switch (f.relocation.type) {
85 _ = options;83 .signed => "X86_64_RELOC_SIGNED",
86 _ = unused_fmt_string;84 .signed1 => "X86_64_RELOC_SIGNED_1",
87 const rel, const cpu_arch = ctx;85 .signed2 => "X86_64_RELOC_SIGNED_2",
88 const str = switch (rel.type) {86 .signed4 => "X86_64_RELOC_SIGNED_4",
89 .signed => "X86_64_RELOC_SIGNED",87 .got_load => "X86_64_RELOC_GOT_LOAD",
90 .signed1 => "X86_64_RELOC_SIGNED_1",88 .tlv => "X86_64_RELOC_TLV",
91 .signed2 => "X86_64_RELOC_SIGNED_2",89 .page => "ARM64_RELOC_PAGE21",
92 .signed4 => "X86_64_RELOC_SIGNED_4",90 .pageoff => "ARM64_RELOC_PAGEOFF12",
93 .got_load => "X86_64_RELOC_GOT_LOAD",91 .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21",
94 .tlv => "X86_64_RELOC_TLV",92 .got_load_pageoff => "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
95 .page => "ARM64_RELOC_PAGE21",93 .tlvp_page => "ARM64_RELOC_TLVP_LOAD_PAGE21",
96 .pageoff => "ARM64_RELOC_PAGEOFF12",94 .tlvp_pageoff => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
97 .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21",95 .branch => switch (f.arch) {
98 .got_load_pageoff => "ARM64_RELOC_GOT_LOAD_PAGEOFF12",96 .x86_64 => "X86_64_RELOC_BRANCH",
99 .tlvp_page => "ARM64_RELOC_TLVP_LOAD_PAGE21",97 .aarch64 => "ARM64_RELOC_BRANCH26",
100 .tlvp_pageoff => "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",98 else => unreachable,
101 .branch => switch (cpu_arch) {99 },
102 .x86_64 => "X86_64_RELOC_BRANCH",100 .got => switch (f.arch) {
103 .aarch64 => "ARM64_RELOC_BRANCH26",101 .x86_64 => "X86_64_RELOC_GOT",
104 else => unreachable,102 .aarch64 => "ARM64_RELOC_POINTER_TO_GOT",
105 },103 else => unreachable,
106 .got => switch (cpu_arch) {104 },
107 .x86_64 => "X86_64_RELOC_GOT",105 .subtractor => switch (f.arch) {
108 .aarch64 => "ARM64_RELOC_POINTER_TO_GOT",106 .x86_64 => "X86_64_RELOC_SUBTRACTOR",
109 else => unreachable,107 .aarch64 => "ARM64_RELOC_SUBTRACTOR",
110 },108 else => unreachable,
111 .subtractor => switch (cpu_arch) {109 },
112 .x86_64 => "X86_64_RELOC_SUBTRACTOR",110 .unsigned => switch (f.arch) {
113 .aarch64 => "ARM64_RELOC_SUBTRACTOR",111 .x86_64 => "X86_64_RELOC_UNSIGNED",
114 else => unreachable,112 .aarch64 => "ARM64_RELOC_UNSIGNED",
115 },113 else => unreachable,
116 .unsigned => switch (cpu_arch) {114 },
117 .x86_64 => "X86_64_RELOC_UNSIGNED",115 });
118 .aarch64 => "ARM64_RELOC_UNSIGNED",116 }
119 else => unreachable,117};
120 },
121 };
122 try writer.writeAll(str);
123}
124118
125pub const Type = enum {119pub const Type = enum {
126 // x86_64120 // x86_64
...@@ -164,10 +158,11 @@ pub const Type = enum {...@@ -164,10 +158,11 @@ pub const Type = enum {
164158
165const Tag = enum { local, @"extern" };159const Tag = enum { local, @"extern" };
166160
161const std = @import("std");
167const assert = std.debug.assert;162const assert = std.debug.assert;
168const macho = std.macho;163const macho = std.macho;
169const math = std.math;164const math = std.math;
170const std = @import("std");165const Writer = std.io.Writer;
171166
172const Atom = @import("Atom.zig");167const Atom = @import("Atom.zig");
173const MachO = @import("../MachO.zig");168const 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...@@ -286,71 +286,51 @@ pub fn setOutputSym(symbol: Symbol, macho_file: *MachO, out: *macho.nlist_64) vo
286 }286 }
287}287}
288288
289pub fn format(289pub fn fmt(symbol: Symbol, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
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) {
308 return .{ .data = .{290 return .{ .data = .{
309 .symbol = symbol,291 .symbol = symbol,
310 .macho_file = macho_file,292 .macho_file = macho_file,
311 } };293 } };
312}294}
313295
314fn format2(296const Format = struct {
315 ctx: FormatContext,297 symbol: Symbol,
316 comptime unused_fmt_string: []const u8,298 macho_file: *MachO,
317 options: std.fmt.FormatOptions,299
318 writer: anytype,300 fn format2(f: Format, w: *Writer) Writer.Error!void {
319) !void {301 const symbol = f.symbol;
320 _ = options;302 try w.print("%{d} : {s} : @{x}", .{
321 _ = unused_fmt_string;303 symbol.nlist_idx,
322 const symbol = ctx.symbol;304 symbol.getName(f.macho_file),
323 try writer.print("%{d} : {s} : @{x}", .{305 symbol.getAddress(.{}, f.macho_file),
324 symbol.nlist_idx,306 });
325 symbol.getName(ctx.macho_file),307 if (symbol.getFile(f.macho_file)) |file| {
326 symbol.getAddress(.{}, ctx.macho_file),308 if (symbol.getOutputSectionIndex(f.macho_file) != 0) {
327 });309 try w.print(" : sect({d})", .{symbol.getOutputSectionIndex(f.macho_file)});
328 if (symbol.getFile(ctx.macho_file)) |file| {310 }
329 if (symbol.getOutputSectionIndex(ctx.macho_file) != 0) {311 if (symbol.getAtom(f.macho_file)) |atom| {
330 try writer.print(" : sect({d})", .{symbol.getOutputSectionIndex(ctx.macho_file)});312 try w.print(" : atom({d})", .{atom.atom_index});
331 }313 }
332 if (symbol.getAtom(ctx.macho_file)) |atom| {314 var buf: [3]u8 = .{'_'} ** 3;
333 try writer.print(" : atom({d})", .{atom.atom_index});315 if (symbol.flags.@"export") buf[0] = 'E';
334 }316 if (symbol.flags.import) buf[1] = 'I';
335 var buf: [3]u8 = .{'_'} ** 3;317 switch (symbol.visibility) {
336 if (symbol.flags.@"export") buf[0] = 'E';318 .local => buf[2] = 'L',
337 if (symbol.flags.import) buf[1] = 'I';319 .hidden => buf[2] = 'H',
338 switch (symbol.visibility) {320 .global => buf[2] = 'G',
339 .local => buf[2] = 'L',321 }
340 .hidden => buf[2] = 'H',322 try w.print(" : {s}", .{&buf});
341 .global => buf[2] = 'G',323 if (symbol.flags.weak) try w.writeAll(" : weak");
342 }324 if (symbol.isSymbolStab(f.macho_file)) try w.writeAll(" : stab");
343 try writer.print(" : {s}", .{&buf});325 switch (file) {
344 if (symbol.flags.weak) try writer.writeAll(" : weak");326 .zig_object => |x| try w.print(" : zig_object({d})", .{x.index}),
345 if (symbol.isSymbolStab(ctx.macho_file)) try writer.writeAll(" : stab");327 .internal => |x| try w.print(" : internal({d})", .{x.index}),
346 switch (file) {328 .object => |x| try w.print(" : object({d})", .{x.index}),
347 .zig_object => |x| try writer.print(" : zig_object({d})", .{x.index}),329 .dylib => |x| try w.print(" : dylib({d})", .{x.index}),
348 .internal => |x| try writer.print(" : internal({d})", .{x.index}),330 }
349 .object => |x| try writer.print(" : object({d})", .{x.index}),331 } else try w.writeAll(" : unresolved");
350 .dylib => |x| try writer.print(" : dylib({d})", .{x.index}),332 }
351 }333};
352 } else try writer.writeAll(" : unresolved");
353}
354334
355pub const Flags = packed struct {335pub const Flags = packed struct {
356 /// Whether the symbol is imported at runtime.336 /// Whether the symbol is imported at runtime.
...@@ -437,6 +417,7 @@ pub const Index = u32;...@@ -437,6 +417,7 @@ pub const Index = u32;
437const assert = std.debug.assert;417const assert = std.debug.assert;
438const macho = std.macho;418const macho = std.macho;
439const std = @import("std");419const std = @import("std");
420const Writer = std.io.Writer;
440421
441const Atom = @import("Atom.zig");422const Atom = @import("Atom.zig");
442const File = @import("file.zig").File;423const 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 {...@@ -20,16 +20,16 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
20 return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;20 return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;
21}21}
2222
23pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {23pub fn write(thunk: Thunk, macho_file: *MachO, bw: *Writer) !void {
24 for (thunk.symbols.keys(), 0..) |ref, i| {24 for (thunk.symbols.keys(), 0..) |ref, i| {
25 const sym = ref.getSymbol(macho_file).?;25 const sym = ref.getSymbol(macho_file).?;
26 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;26 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
27 const taddr = sym.getAddress(.{}, macho_file);27 const taddr = sym.getAddress(.{}, macho_file);
28 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));28 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
29 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);29 try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
30 const off: u12 = @truncate(taddr);30 const off: u12 = @truncate(taddr);
31 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);31 try bw.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
32 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);32 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
33 }33 }
34}34}
3535
...@@ -61,47 +61,27 @@ pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void {...@@ -61,47 +61,27 @@ pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void {
61 }61 }
62}62}
6363
64pub fn format(64pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
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) {
78 return .{ .data = .{65 return .{ .data = .{
79 .thunk = thunk,66 .thunk = thunk,
80 .macho_file = macho_file,67 .macho_file = macho_file,
81 } };68 } };
82}69}
8370
84const FormatContext = struct {71const Format = struct {
85 thunk: Thunk,72 thunk: Thunk,
86 macho_file: *MachO,73 macho_file: *MachO,
87};
8874
89fn format2(75 fn default(f: Format, w: *Writer) Writer.Error!void {
90 ctx: FormatContext,76 const thunk = f.thunk;
91 comptime unused_fmt_string: []const u8,77 const macho_file = f.macho_file;
92 options: std.fmt.FormatOptions,78 try w.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
93 writer: anytype,79 for (thunk.symbols.keys()) |ref| {
94) !void {80 const sym = ref.getSymbol(macho_file).?;
95 _ = options;81 try w.print(" {f} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
96 _ = unused_fmt_string;82 }
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 });
103 }83 }
104}84};
10585
106const trampoline_size = 3 * @sizeOf(u32);86const trampoline_size = 3 * @sizeOf(u32);
10787
...@@ -115,6 +95,7 @@ const math = std.math;...@@ -115,6 +95,7 @@ const math = std.math;
115const mem = std.mem;95const mem = std.mem;
116const std = @import("std");96const std = @import("std");
117const trace = @import("../../tracy.zig").trace;97const trace = @import("../../tracy.zig").trace;
98const Writer = std.io.Writer;
11899
119const Allocator = mem.Allocator;100const Allocator = mem.Allocator;
120const Atom = @import("Atom.zig");101const Atom = @import("Atom.zig");
src/link/MachO/UnwindInfo.zig+46-97
...@@ -133,7 +133,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {...@@ -133,7 +133,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
133 for (info.records.items) |ref| {133 for (info.records.items) |ref| {
134 const rec = ref.getUnwindRecord(macho_file);134 const rec = ref.getUnwindRecord(macho_file);
135 const atom = rec.getAtom(macho_file);135 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}", .{
137 rec.getAtomAddress(macho_file),137 rec.getAtomAddress(macho_file),
138 rec.getAtomAddress(macho_file) + rec.length,138 rec.getAtomAddress(macho_file) + rec.length,
139 atom.getName(macho_file),139 atom.getName(macho_file),
...@@ -202,7 +202,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {...@@ -202,7 +202,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
202 if (i >= max_common_encodings) break;202 if (i >= max_common_encodings) break;
203 if (slice[i].count < 2) continue;203 if (slice[i].count < 2) continue;
204 info.appendCommonEncoding(slice[i].enc);204 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 });
206 }206 }
207 }207 }
208208
...@@ -255,7 +255,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {...@@ -255,7 +255,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
255 page.kind = .compressed;255 page.kind = .compressed;
256 }256 }
257257
258 log.debug("{}", .{page.fmt(info.*)});258 log.debug("{f}", .{page.fmt(info.*)});
259259
260 try info.pages.append(gpa, page);260 try info.pages.append(gpa, page);
261 }261 }
...@@ -289,13 +289,10 @@ pub fn calcSize(info: UnwindInfo) usize {...@@ -289,13 +289,10 @@ pub fn calcSize(info: UnwindInfo) usize {
289 return total_size;289 return total_size;
290}290}
291291
292pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {292pub fn write(info: UnwindInfo, macho_file: *MachO, bw: *Writer) Writer.Error!void {
293 const seg = macho_file.getTextSegment();293 const seg = macho_file.getTextSegment();
294 const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];294 const header = macho_file.sections.items(.header)[macho_file.unwind_info_sect_index.?];
295295
296 var stream = std.io.fixedBufferStream(buffer);
297 const writer = stream.writer();
298
299 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);296 const common_encodings_offset: u32 = @sizeOf(macho.unwind_info_section_header);
300 const common_encodings_count: u32 = info.common_encodings_count;297 const common_encodings_count: u32 = info.common_encodings_count;
301 const personalities_offset: u32 = common_encodings_offset + common_encodings_count * @sizeOf(u32);298 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 {...@@ -303,7 +300,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
303 const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);300 const indexes_offset: u32 = personalities_offset + personalities_count * @sizeOf(u32);
304 const indexes_count: u32 = @as(u32, @intCast(info.pages.items.len + 1));301 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{
307 .commonEncodingsArraySectionOffset = common_encodings_offset,304 .commonEncodingsArraySectionOffset = common_encodings_offset,
308 .commonEncodingsArrayCount = common_encodings_count,305 .commonEncodingsArrayCount = common_encodings_count,
309 .personalityArraySectionOffset = personalities_offset,306 .personalityArraySectionOffset = personalities_offset,
...@@ -312,11 +309,11 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -312,11 +309,11 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
312 .indexCount = indexes_count,309 .indexCount = indexes_count,
313 });310 });
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
317 for (info.personalities[0..info.personalities_count]) |ref| {314 for (info.personalities[0..info.personalities_count]) |ref| {
318 const sym = ref.getSymbol(macho_file).?;315 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);
320 }317 }
321318
322 const pages_base_offset = @as(u32, @intCast(header.size - (info.pages.items.len * second_level_page_bytes)));319 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 {...@@ -325,7 +322,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
325 for (info.pages.items, 0..) |page, i| {322 for (info.pages.items, 0..) |page, i| {
326 assert(page.count > 0);323 assert(page.count > 0);
327 const rec = info.records.items[page.start].getUnwindRecord(macho_file);324 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{
329 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),326 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
330 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),327 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
331 .lsdaIndexArraySectionOffset = lsda_base_offset +328 .lsdaIndexArraySectionOffset = lsda_base_offset +
...@@ -335,7 +332,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -335,7 +332,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
335332
336 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);333 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);
337 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));334 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{
339 .functionOffset = sentinel_address,336 .functionOffset = sentinel_address,
340 .secondLevelPagesSectionOffset = 0,337 .secondLevelPagesSectionOffset = 0,
341 .lsdaIndexArraySectionOffset = lsda_base_offset +338 .lsdaIndexArraySectionOffset = lsda_base_offset +
...@@ -344,23 +341,20 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -344,23 +341,20 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
344341
345 for (info.lsdas.items) |index| {342 for (info.lsdas.items) |index| {
346 const rec = info.records.items[index].getUnwindRecord(macho_file);343 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{
348 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),345 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
349 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),346 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),
350 });347 });
351 }348 }
352349
353 for (info.pages.items) |page| {350 for (info.pages.items) |page| {
354 const start = stream.pos;351 const start = bw.count;
355 try page.write(info, macho_file, writer);352 try page.write(info, macho_file, bw);
356 const nwritten = stream.pos - start;353 const nwritten = bw.count - start;
357 if (nwritten < second_level_page_bytes) {354 try bw.splatByteAll(0, math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow);
358 const padding = math.cast(usize, second_level_page_bytes - nwritten) orelse return error.Overflow;
359 try writer.writeByteNTimes(0, padding);
360 }
361 }355 }
362356
363 @memset(buffer[stream.pos..], 0);357 @memset(bw.unusedCapacitySlice(), 0);
364}358}
365359
366fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {360fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 {
...@@ -455,15 +449,9 @@ pub const Encoding = extern struct {...@@ -455,15 +449,9 @@ pub const Encoding = extern struct {
455 return enc.enc == other.enc;449 return enc.enc == other.enc;
456 }450 }
457451
458 pub fn format(452 pub fn format(enc: Encoding, w: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void {
459 enc: Encoding,453 comptime assert(unused_fmt_string.len == 0);
460 comptime unused_fmt_string: []const u8,454 try w.print("0x{x:0>8}", .{enc.enc});
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});
467 }455 }
468};456};
469457
...@@ -517,48 +505,28 @@ pub const Record = struct {...@@ -517,48 +505,28 @@ pub const Record = struct {
517 return lsda.getAddress(macho_file) + rec.lsda_offset;505 return lsda.getAddress(macho_file) + rec.lsda_offset;
518 }506 }
519507
520 pub fn format(508 pub fn fmt(rec: Record, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
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) {
534 return .{ .data = .{509 return .{ .data = .{
535 .rec = rec,510 .rec = rec,
536 .macho_file = macho_file,511 .macho_file = macho_file,
537 } };512 } };
538 }513 }
539514
540 const FormatContext = struct {515 const Format = struct {
541 rec: Record,516 rec: Record,
542 macho_file: *MachO,517 macho_file: *MachO,
543 };
544518
545 fn format2(519 fn default(f: Format, w: *Writer) Writer.Error!void {
546 ctx: FormatContext,520 const rec = f.rec;
547 comptime unused_fmt_string: []const u8,521 const macho_file = f.macho_file;
548 options: std.fmt.FormatOptions,522 try w.print("{x} : len({x})", .{
549 writer: anytype,523 rec.enc.enc, rec.length,
550 ) !void {524 });
551 _ = unused_fmt_string;525 if (rec.enc.isDwarf(macho_file)) try w.print(" : fde({d})", .{rec.fde});
552 _ = options;526 try w.print(" : {s}", .{rec.getAtom(macho_file).getName(macho_file)});
553 const rec = ctx.rec;527 if (!rec.alive) try w.writeAll(" : [*]");
554 const macho_file = ctx.macho_file;528 }
555 try writer.print("{x} : len({x})", .{529 };
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 }
562530
563 pub const Index = u32;531 pub const Index = u32;
564532
...@@ -613,45 +581,25 @@ const Page = struct {...@@ -613,45 +581,25 @@ const Page = struct {
613 return null;581 return null;
614 }582 }
615583
616 fn format(584 const Format = struct {
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 {
630 page: Page,585 page: Page,
631 info: UnwindInfo,586 info: UnwindInfo,
632 };
633587
634 fn format2(588 fn default(f: Format, w: *Writer) Writer.Error!void {
635 ctx: FormatPageContext,589 try w.writeAll("Page:\n");
636 comptime unused_format_string: []const u8,590 try w.print(" kind: {s}\n", .{@tagName(f.page.kind)});
637 options: std.fmt.FormatOptions,591 try w.print(" entries: {d} - {d}\n", .{
638 writer: anytype,592 f.page.start,
639 ) @TypeOf(writer).Error!void {593 f.page.start + f.page.count,
640 _ = options;594 });
641 _ = unused_format_string;595 try w.print(" encodings (count = {d})\n", .{f.page.page_encodings_count});
642 try writer.writeAll("Page:\n");596 for (f.page.page_encodings[0..f.page.page_encodings_count], 0..) |enc, i| {
643 try writer.print(" kind: {s}\n", .{@tagName(ctx.page.kind)});597 try w.print(" {d}: {f}\n", .{ f.info.common_encodings_count + i, enc });
644 try writer.print(" entries: {d} - {d}\n", .{598 }
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 });
651 }599 }
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) {
655 return .{ .data = .{603 return .{ .data = .{
656 .page = page,604 .page = page,
657 .info = info,605 .info = info,
...@@ -720,6 +668,7 @@ const macho = std.macho;...@@ -720,6 +668,7 @@ const macho = std.macho;
720const math = std.math;668const math = std.math;
721const mem = std.mem;669const mem = std.mem;
722const trace = @import("../../tracy.zig").trace;670const trace = @import("../../tracy.zig").trace;
671const Writer = std.io.Writer;
723672
724const Allocator = mem.Allocator;673const Allocator = mem.Allocator;
725const Atom = @import("Atom.zig");674const Atom = @import("Atom.zig");
src/link/MachO/ZigObject.zig+36-51
...@@ -317,12 +317,12 @@ pub fn updateArSize(self: *ZigObject) void {...@@ -317,12 +317,12 @@ pub fn updateArSize(self: *ZigObject) void {
317 self.output_ar_state.size = self.data.items.len;317 self.output_ar_state.size = self.data.items.len;
318}318}
319319
320pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void {320pub fn writeAr(self: ZigObject, bw: *Writer, ar_format: Archive.Format) Writer.Error!void {
321 // Header321 // Header
322 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;322 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
323 try Archive.writeHeader(self.basename, size, ar_format, writer);323 try Archive.writeHeader(bw, self.basename, size, ar_format);
324 // Data324 // Data
325 try writer.writeAll(self.data.items);325 try bw.writeAll(self.data.items);
326}326}
327327
328pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void {328pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void {
...@@ -618,7 +618,7 @@ pub fn getNavVAddr(...@@ -618,7 +618,7 @@ pub fn getNavVAddr(
618 const zcu = pt.zcu;618 const zcu = pt.zcu;
619 const ip = &zcu.intern_pool;619 const ip = &zcu.intern_pool;
620 const nav = ip.getNav(nav_index);620 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 });
622 const sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(622 const sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(
623 macho_file,623 macho_file,
624 nav.name.toSlice(ip),624 nav.name.toSlice(ip),
...@@ -884,7 +884,6 @@ pub fn updateNav(...@@ -884,7 +884,6 @@ pub fn updateNav(
884 defer debug_wip_nav.deinit();884 defer debug_wip_nav.deinit();
885 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {885 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
886 error.OutOfMemory => return error.OutOfMemory,886 error.OutOfMemory => return error.OutOfMemory,
887 error.Overflow => return error.Overflow,
888 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),887 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
889 };888 };
890 }889 }
...@@ -921,7 +920,6 @@ pub fn updateNav(...@@ -921,7 +920,6 @@ pub fn updateNav(
921920
922 if (debug_wip_nav) |*wip_nav| self.dwarf.?.finishWipNav(pt, nav_index, wip_nav) catch |err| switch (err) {921 if (debug_wip_nav) |*wip_nav| self.dwarf.?.finishWipNav(pt, nav_index, wip_nav) catch |err| switch (err) {
923 error.OutOfMemory => return error.OutOfMemory,922 error.OutOfMemory => return error.OutOfMemory,
924 error.Overflow => return error.Overflow,
925 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),923 else => |e| return macho_file.base.cgFail(nav_index, "failed to finish dwarf nav: {s}", .{@errorName(e)}),
926 };924 };
927 } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index);925 } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index);
...@@ -943,7 +941,7 @@ fn updateNavCode(...@@ -943,7 +941,7 @@ fn updateNavCode(
943 const ip = &zcu.intern_pool;941 const ip = &zcu.intern_pool;
944 const nav = ip.getNav(nav_index);942 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
948 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;946 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
949 const required_alignment = switch (pt.navAlignment(nav_index)) {947 const required_alignment = switch (pt.navAlignment(nav_index)) {
...@@ -981,7 +979,7 @@ fn updateNavCode(...@@ -981,7 +979,7 @@ fn updateNavCode(
981 if (need_realloc) {979 if (need_realloc) {
982 atom.grow(macho_file) catch |err|980 atom.grow(macho_file) catch |err|
983 return macho_file.base.cgFail(nav_index, "failed to grow atom: {s}", .{@errorName(err)});981 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 });
985 if (old_vaddr != atom.value) {983 if (old_vaddr != atom.value) {
986 sym.value = 0;984 sym.value = 0;
987 nlist.n_value = 0;985 nlist.n_value = 0;
...@@ -1023,7 +1021,7 @@ fn updateTlv(...@@ -1023,7 +1021,7 @@ fn updateTlv(
1023 const ip = &pt.zcu.intern_pool;1021 const ip = &pt.zcu.intern_pool;
1024 const nav = ip.getNav(nav_index);1022 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
1028 // 1. Lower TLV initializer1026 // 1. Lower TLV initializer
1029 const init_sym_index = try self.createTlvInitializer(1027 const init_sym_index = try self.createTlvInitializer(
...@@ -1351,7 +1349,7 @@ fn updateLazySymbol(...@@ -1351,7 +1349,7 @@ fn updateLazySymbol(
1351 defer code_buffer.deinit(gpa);1349 defer code_buffer.deinit(gpa);
13521350
1353 const name_str = blk: {1351 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}", .{
1355 @tagName(lazy_sym.kind),1353 @tagName(lazy_sym.kind),
1356 Type.fromInterned(lazy_sym.ty).fmt(pt),1354 Type.fromInterned(lazy_sym.ty).fmt(pt),
1357 });1355 });
...@@ -1430,7 +1428,7 @@ pub fn deleteExport(...@@ -1430,7 +1428,7 @@ pub fn deleteExport(
1430 } orelse return;1428 } orelse return;
1431 const nlist_index = metadata.@"export"(self, name.toSlice(&zcu.intern_pool)) orelse return;1429 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
1435 const nlist = &self.symtab.items(.nlist)[nlist_index.*];1433 const nlist = &self.symtab.items(.nlist)[nlist_index.*];
1436 self.symtab.items(.size)[nlist_index.*] = 0;1434 self.symtab.items(.size)[nlist_index.*] = 0;
...@@ -1678,64 +1676,50 @@ pub fn asFile(self: *ZigObject) File {...@@ -1678,64 +1676,50 @@ pub fn asFile(self: *ZigObject) File {
1678 return .{ .zig_object = self };1676 return .{ .zig_object = self };
1679}1677}
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) {
1682 return .{ .data = .{1680 return .{ .data = .{
1683 .self = self,1681 .self = self,
1684 .macho_file = macho_file,1682 .macho_file = macho_file,
1685 } };1683 } };
1686}1684}
16871685
1688const FormatContext = struct {1686const Format = struct {
1689 self: *ZigObject,1687 self: *ZigObject,
1690 macho_file: *MachO,1688 macho_file: *MachO,
1691};
16921689
1693fn formatSymtab(1690 fn symtab(f: Format, w: *Writer) Writer.Error!void {
1694 ctx: FormatContext,1691 try w.writeAll(" symbols\n");
1695 comptime unused_fmt_string: []const u8,1692 const self = f.self;
1696 options: std.fmt.FormatOptions,1693 const macho_file = f.macho_file;
1697 writer: anytype,1694 for (self.symbols.items, 0..) |sym, i| {
1698) !void {1695 const ref = self.getSymbolRef(@intCast(i), macho_file);
1699 _ = unused_fmt_string;1696 if (ref.getFile(macho_file) == null) {
1700 _ = options;1697 // TODO any better way of handling this?
1701 try writer.writeAll(" symbols\n");1698 try w.print(" {s} : unclaimed\n", .{sym.getName(macho_file)});
1702 const self = ctx.self;1699 } else {
1703 const macho_file = ctx.macho_file;1700 try w.print(" {f}\n", .{ref.getSymbol(macho_file).?.fmt(macho_file)});
1704 for (self.symbols.items, 0..) |sym, i| {1701 }
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)});
1711 }1702 }
1712 }1703 }
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) {
1716 return .{ .data = .{1717 return .{ .data = .{
1717 .self = self,1718 .self = self,
1718 .macho_file = macho_file,1719 .macho_file = macho_file,
1719 } };1720 } };
1720}1721}
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
1739const AvMetadata = struct {1723const AvMetadata = struct {
1740 symbol_index: Symbol.Index,1724 symbol_index: Symbol.Index,
1741 /// A list of all exports aliases of this Av.1725 /// A list of all exports aliases of this Av.
...@@ -1797,6 +1781,7 @@ const mem = std.mem;...@@ -1797,6 +1781,7 @@ const mem = std.mem;
1797const target_util = @import("../../target.zig");1781const target_util = @import("../../target.zig");
1798const trace = @import("../../tracy.zig").trace;1782const trace = @import("../../tracy.zig").trace;
1799const std = @import("std");1783const std = @import("std");
1784const Writer = std.io.Writer;
18001785
1801const Allocator = std.mem.Allocator;1786const Allocator = std.mem.Allocator;
1802const Archive = @import("Archive.zig");1787const 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 {...@@ -117,7 +117,7 @@ fn mark(roots: []*Atom, objects: []const File.Index, macho_file: *MachO) void {
117fn markLive(atom: *Atom, macho_file: *MachO) void {117fn markLive(atom: *Atom, macho_file: *MachO) void {
118 assert(atom.visited.load(.seq_cst));118 assert(atom.visited.load(.seq_cst));
119 atom.setAlive(true);119 atom.setAlive(true);
120 track_live_log.debug("{}marking live atom({d},{s})", .{120 track_live_log.debug("{f}marking live atom({d},{s})", .{
121 track_live_level,121 track_live_level,
122 atom.atom_index,122 atom.atom_index,
123 atom.getName(macho_file),123 atom.getName(macho_file),
...@@ -196,15 +196,9 @@ const Level = struct {...@@ -196,15 +196,9 @@ const Level = struct {
196 self.value += 1;196 self.value += 1;
197 }197 }
198198
199 pub fn format(199 pub fn format(self: *const @This(), bw: *Writer, comptime unused_fmt_string: []const u8) Writer.Error!void {
200 self: *const @This(),
201 comptime unused_fmt_string: []const u8,
202 options: std.fmt.FormatOptions,
203 writer: anytype,
204 ) !void {
205 _ = unused_fmt_string;200 _ = unused_fmt_string;
206 _ = options;201 try bw.splatByteAll(' ', self.value);
207 try writer.writeByteNTimes(' ', self.value);
208 }202 }
209};203};
210204
...@@ -219,6 +213,7 @@ const mem = std.mem;...@@ -219,6 +213,7 @@ const mem = std.mem;
219const trace = @import("../../tracy.zig").trace;213const trace = @import("../../tracy.zig").trace;
220const track_live_log = std.log.scoped(.dead_strip_track_live);214const track_live_log = std.log.scoped(.dead_strip_track_live);
221const std = @import("std");215const std = @import("std");
216const Writer = std.io.Writer;
222217
223const Allocator = mem.Allocator;218const Allocator = mem.Allocator;
224const Atom = @import("Atom.zig");219const Atom = @import("Atom.zig");
src/link/MachO/dyld_info/Rebase.zig+48-47
...@@ -3,7 +3,7 @@ buffer: std.ArrayListUnmanaged(u8) = .empty,...@@ -3,7 +3,7 @@ buffer: std.ArrayListUnmanaged(u8) = .empty,
33
4pub const Entry = struct {4pub const Entry = struct {
5 offset: u64,5 offset: u64,
6 segment_id: u8,6 segment_id: u4,
77
8 pub fn lessThan(ctx: void, entry: Entry, other: Entry) bool {8 pub fn lessThan(ctx: void, entry: Entry, other: Entry) bool {
9 _ = ctx;9 _ = ctx;
...@@ -110,33 +110,35 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {...@@ -110,33 +110,35 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
110fn finalize(rebase: *Rebase, gpa: Allocator) !void {110fn finalize(rebase: *Rebase, gpa: Allocator) !void {
111 if (rebase.entries.items.len == 0) return;111 if (rebase.entries.items.len == 0) return;
112112
113 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
115 log.debug("rebase opcodes", .{});117 log.debug("rebase opcodes", .{});
116118
117 std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);119 std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan);
118120
119 try setTypePointer(writer);121 try setTypePointer(bw);
120122
121 var start: usize = 0;123 var start: usize = 0;
122 var seg_id: ?u8 = null;124 var seg_id: ?u8 = null;
123 for (rebase.entries.items, 0..) |entry, i| {125 for (rebase.entries.items, 0..) |entry, i| {
124 if (seg_id != null and seg_id.? == entry.segment_id) continue;126 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);
126 seg_id = entry.segment_id;128 seg_id = entry.segment_id;
127 start = i;129 start = i;
128 }130 }
129131
130 try finalizeSegment(rebase.entries.items[start..], writer);132 try finalizeSegment(rebase.entries.items[start..], bw);
131 try done(writer);133 try done(bw);
132}134}
133135
134fn finalizeSegment(entries: []const Entry, writer: anytype) !void {136fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void {
135 if (entries.len == 0) return;137 if (entries.len == 0) return;
136138
137 const segment_id = entries[0].segment_id;139 const segment_id = entries[0].segment_id;
138 var offset = entries[0].offset;140 var offset = entries[0].offset;
139 try setSegmentOffset(segment_id, offset, writer);141 try setSegmentOffset(segment_id, offset, bw);
140142
141 var count: usize = 0;143 var count: usize = 0;
142 var skip: u64 = 0;144 var skip: u64 = 0;
...@@ -155,7 +157,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {...@@ -155,7 +157,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
155 .start => {157 .start => {
156 if (offset < current_offset) {158 if (offset < current_offset) {
157 const delta = current_offset - offset;159 const delta = current_offset - offset;
158 try addAddr(delta, writer);160 try addAddr(delta, bw);
159 offset += delta;161 offset += delta;
160 }162 }
161 state = .times;163 state = .times;
...@@ -175,7 +177,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {...@@ -175,7 +177,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
175 offset += skip;177 offset += skip;
176 i -= 1;178 i -= 1;
177 } else {179 } else {
178 try rebaseTimes(count, writer);180 try rebaseTimes(count, bw);
179 state = .start;181 state = .start;
180 i -= 1;182 i -= 1;
181 }183 }
...@@ -184,9 +186,9 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {...@@ -184,9 +186,9 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
184 if (current_offset < offset) {186 if (current_offset < offset) {
185 count -= 1;187 count -= 1;
186 if (count == 1) {188 if (count == 1) {
187 try rebaseAddAddr(skip, writer);189 try rebaseAddAddr(skip, bw);
188 } else {190 } else {
189 try rebaseTimesSkip(count, skip, writer);191 try rebaseTimesSkip(count, skip, bw);
190 }192 }
191 state = .start;193 state = .start;
192 offset = offset - (@sizeOf(u64) + skip);194 offset = offset - (@sizeOf(u64) + skip);
...@@ -199,7 +201,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {...@@ -199,7 +201,7 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
199 count += 1;201 count += 1;
200 offset += @sizeOf(u64) + skip;202 offset += @sizeOf(u64) + skip;
201 } else {203 } else {
202 try rebaseTimesSkip(count, skip, writer);204 try rebaseTimesSkip(count, skip, bw);
203 state = .start;205 state = .start;
204 i -= 1;206 i -= 1;
205 }207 }
...@@ -210,68 +212,66 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {...@@ -210,68 +212,66 @@ fn finalizeSegment(entries: []const Entry, writer: anytype) !void {
210 switch (state) {212 switch (state) {
211 .start => unreachable,213 .start => unreachable,
212 .times => {214 .times => {
213 try rebaseTimes(count, writer);215 try rebaseTimes(count, bw);
214 },216 },
215 .times_skip => {217 .times_skip => {
216 try rebaseTimesSkip(count, skip, writer);218 try rebaseTimesSkip(count, skip, bw);
217 },219 },
218 }220 }
219}221}
220222
221fn setTypePointer(writer: anytype) !void {223fn setTypePointer(bw: *Writer) Writer.Error!void {
222 log.debug(">>> set type: {d}", .{macho.REBASE_TYPE_POINTER});224 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)));
224}226}
225227
226fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {228fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {
227 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });229 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)));230 try bw.writeByte(macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | @as(u4, @truncate(segment_id)));
229 try std.leb.writeUleb128(writer, offset);231 try bw.writeLeb128(offset);
230}232}
231233
232fn rebaseAddAddr(addr: u64, writer: anytype) !void {234fn rebaseAddAddr(addr: u64, bw: *Writer) Writer.Error!void {
233 log.debug(">>> rebase with add: {x}", .{addr});235 log.debug(">>> rebase with add: {x}", .{addr});
234 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);236 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB);
235 try std.leb.writeUleb128(writer, addr);237 try bw.writeLeb128(addr);
236}238}
237239
238fn rebaseTimes(count: usize, writer: anytype) !void {240fn rebaseTimes(count: usize, bw: *Writer) Writer.Error!void {
239 log.debug(">>> rebase with count: {d}", .{count});241 log.debug(">>> rebase with count: {d}", .{count});
240 if (count <= 0xf) {242 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)));
242 } else {244 } else {
243 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);245 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES);
244 try std.leb.writeUleb128(writer, count);246 try bw.writeLeb128(count);
245 }247 }
246}248}
247249
248fn rebaseTimesSkip(count: usize, skip: u64, writer: anytype) !void {250fn rebaseTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {
249 log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip });251 log.debug(">>> rebase with count: {d} and skip: {x}", .{ count, skip });
250 try writer.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);252 try bw.writeByte(macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB);
251 try std.leb.writeUleb128(writer, count);253 try bw.writeLeb128(count);
252 try std.leb.writeUleb128(writer, skip);254 try bw.writeLeb128(skip);
253}255}
254256
255fn addAddr(addr: u64, writer: anytype) !void {257fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {
256 log.debug(">>> add: {x}", .{addr});258 log.debug(">>> add: {x}", .{addr});
257 if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {259 if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| {
258 const imm = @divExact(addr, @sizeOf(u64));260 if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte(
259 if (imm <= 0xf) {261 macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | imm_scaled,
260 try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)));262 );
261 return;263 } else |_| {}
262 }264 try bw.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);
263 }265 try bw.writeLeb128(addr);
264 try writer.writeByte(macho.REBASE_OPCODE_ADD_ADDR_ULEB);
265 try std.leb.writeUleb128(writer, addr);
266}266}
267267
268fn done(writer: anytype) !void {268fn done(bw: *Writer) Writer.Error!void {
269 log.debug(">>> done", .{});269 log.debug(">>> done", .{});
270 try writer.writeByte(macho.REBASE_OPCODE_DONE);270 try bw.writeByte(macho.REBASE_OPCODE_DONE);
271}271}
272272
273pub fn write(rebase: Rebase, writer: anytype) !void {273pub fn write(rebase: Rebase, bw: *Writer) Writer.Error!void {
274 try writer.writeAll(rebase.buffer.items);274 try bw.writeAll(rebase.buffer.items);
275}275}
276276
277test "rebase - no entries" {277test "rebase - no entries" {
...@@ -654,9 +654,10 @@ const log = std.log.scoped(.link_dyld_info);...@@ -654,9 +654,10 @@ const log = std.log.scoped(.link_dyld_info);
654const macho = std.macho;654const macho = std.macho;
655const mem = std.mem;655const mem = std.mem;
656const testing = std.testing;656const testing = std.testing;
657const trace = @import("../../../tracy.zig").trace;
658
659const Allocator = mem.Allocator;657const Allocator = mem.Allocator;
658const Writer = std.io.Writer;
659
660const trace = @import("../../../tracy.zig").trace;
660const File = @import("../file.zig").File;661const File = @import("../file.zig").File;
661const MachO = @import("../../MachO.zig");662const MachO = @import("../../MachO.zig");
662const Rebase = @This();663const Rebase = @This();
src/link/MachO/dyld_info/Trie.zig+32-37
...@@ -31,7 +31,7 @@...@@ -31,7 +31,7 @@
3131
32/// The root node of the trie.32/// The root node of the trie.
33root: ?Node.Index = null,33root: ?Node.Index = null,
34buffer: std.ArrayListUnmanaged(u8) = .empty,34buffer: []u8 = &.{},
35nodes: std.MultiArrayList(Node) = .{},35nodes: std.MultiArrayList(Node) = .{},
36edges: std.ArrayListUnmanaged(Edge) = .empty,36edges: std.ArrayListUnmanaged(Edge) = .empty,
3737
...@@ -123,7 +123,7 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void {...@@ -123,7 +123,7 @@ pub fn updateSize(self: *Trie, macho_file: *MachO) !void {
123123
124 try self.finalize(gpa);124 try self.finalize(gpa);
125125
126 macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));126 macho_file.dyld_info_cmd.export_size = mem.alignForward(u32, @intCast(self.buffer.len), @alignOf(u64));
127}127}
128128
129/// Finalizes this trie for writing to a byte stream.129/// Finalizes this trie for writing to a byte stream.
...@@ -138,7 +138,7 @@ fn finalize(self: *Trie, allocator: Allocator) !void {...@@ -138,7 +138,7 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
138 defer ordered_nodes.deinit();138 defer ordered_nodes.deinit();
139 try ordered_nodes.ensureTotalCapacityPrecise(self.nodes.items(.is_terminal).len);139 try ordered_nodes.ensureTotalCapacityPrecise(self.nodes.items(.is_terminal).len);
140140
141 var fifo = std.fifo.LinearFifo(Node.Index, .Dynamic).init(allocator);141 var fifo = DeprecatedLinearFifo(Node.Index).init(allocator);
142 defer fifo.deinit();142 defer fifo.deinit();
143143
144 try fifo.writeItem(self.root.?);144 try fifo.writeItem(self.root.?);
...@@ -164,9 +164,11 @@ fn finalize(self: *Trie, allocator: Allocator) !void {...@@ -164,9 +164,11 @@ fn finalize(self: *Trie, allocator: Allocator) !void {
164 }164 }
165 }165 }
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);
168 for (ordered_nodes.items) |node_index| {170 for (ordered_nodes.items) |node_index| {
169 try self.writeNode(node_index, self.buffer.writer(allocator));171 try self.writeNode(node_index, &bw);
170 }172 }
171}173}
172174
...@@ -181,17 +183,17 @@ const FinalizeNodeResult = struct {...@@ -181,17 +183,17 @@ const FinalizeNodeResult = struct {
181183
182/// Updates offset of this node in the output byte stream.184/// Updates offset of this node in the output byte stream.
183fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult {185fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult {
184 var stream = std.io.countingWriter(std.io.null_writer);186 var buf: [1024]u8 = undefined;
185 const writer = stream.writer();187 var bw: Writer = .discarding(&buf);
186 const slice = self.nodes.slice();188 const slice = self.nodes.slice();
187189
188 var node_size: u32 = 0;190 var node_size: u32 = 0;
189 if (slice.items(.is_terminal)[node_index]) {191 if (slice.items(.is_terminal)[node_index]) {
190 const export_flags = slice.items(.export_flags)[node_index];192 const export_flags = slice.items(.export_flags)[node_index];
191 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];193 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
192 try leb.writeULEB128(writer, export_flags);194 try bw.writeLeb128(export_flags);
193 try leb.writeULEB128(writer, vmaddr_offset);195 try bw.writeLeb128(vmaddr_offset);
194 try leb.writeULEB128(writer, stream.bytes_written);196 try bw.writeLeb128(bw.count);
195 } else {197 } else {
196 node_size += 1; // 0x0 for non-terminal nodes198 node_size += 1; // 0x0 for non-terminal nodes
197 }199 }
...@@ -201,13 +203,13 @@ fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !Final...@@ -201,13 +203,13 @@ fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !Final
201 const edge = &self.edges.items[edge_index];203 const edge = &self.edges.items[edge_index];
202 const next_node_offset = slice.items(.trie_offset)[edge.node];204 const next_node_offset = slice.items(.trie_offset)[edge.node];
203 node_size += @intCast(edge.label.len + 1);205 node_size += @intCast(edge.label.len + 1);
204 try leb.writeULEB128(writer, next_node_offset);206 try bw.writeLeb128(next_node_offset);
205 }207 }
206208
207 const trie_offset = slice.items(.trie_offset)[node_index];209 const trie_offset = slice.items(.trie_offset)[node_index];
208 const updated = offset_in_trie != trie_offset;210 const updated = offset_in_trie != trie_offset;
209 slice.items(.trie_offset)[node_index] = offset_in_trie;211 slice.items(.trie_offset)[node_index] = offset_in_trie;
210 node_size += @intCast(stream.bytes_written);212 node_size += @intCast(bw.count);
211213
212 return .{ .node_size = node_size, .updated = updated };214 return .{ .node_size = node_size, .updated = updated };
213}215}
...@@ -223,12 +225,11 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {...@@ -223,12 +225,11 @@ pub fn deinit(self: *Trie, allocator: Allocator) void {
223 }225 }
224 self.nodes.deinit(allocator);226 self.nodes.deinit(allocator);
225 self.edges.deinit(allocator);227 self.edges.deinit(allocator);
226 self.buffer.deinit(allocator);228 allocator.free(self.buffer);
227}229}
228230
229pub fn write(self: Trie, writer: anytype) !void {231pub fn write(self: Trie, bw: *Writer) Writer.Error!void {
230 if (self.buffer.items.len == 0) return;232 try bw.writeAll(self.buffer);
231 try writer.writeAll(self.buffer.items);
232}233}
233234
234/// Writes this node to a byte stream.235/// Writes this node to a byte stream.
...@@ -237,7 +238,7 @@ pub fn write(self: Trie, writer: anytype) !void {...@@ -237,7 +238,7 @@ pub fn write(self: Trie, writer: anytype) !void {
237/// iterate over `Trie.ordered_nodes` and call this method on each node.238/// iterate over `Trie.ordered_nodes` and call this method on each node.
238/// This is one of the requirements of the MachO.239/// This is one of the requirements of the MachO.
239/// Panics if `finalize` was not called before calling this method.240/// 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 {
241 const slice = self.nodes.slice();242 const slice = self.nodes.slice();
242 const edges = slice.items(.edges)[node_index];243 const edges = slice.items(.edges)[node_index];
243 const is_terminal = slice.items(.is_terminal)[node_index];244 const is_terminal = slice.items(.is_terminal)[node_index];
...@@ -245,36 +246,28 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {...@@ -245,36 +246,28 @@ fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void {
245 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];246 const vmaddr_offset = slice.items(.vmaddr_offset)[node_index];
246247
247 if (is_terminal) {248 if (is_terminal) {
248 // Terminal node info: encode export flags and vmaddr offset of this symbol.249 const start = bw.count;
249 var info_buf: [@sizeOf(u64) * 2]u8 = undefined;
250 var info_stream = std.io.fixedBufferStream(&info_buf);
251 // TODO Implement for special flags.250 // TODO Implement for special flags.
252 assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and251 assert(export_flags & macho.EXPORT_SYMBOL_FLAGS_REEXPORT == 0 and
253 export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);252 export_flags & macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER == 0);
254 try leb.writeULEB128(info_stream.writer(), export_flags);253 // Terminal node info: encode export flags and vmaddr offset of this symbol.
255 try leb.writeULEB128(info_stream.writer(), vmaddr_offset);254 try bw.writeLeb128(export_flags);
256255 try bw.writeLeb128(vmaddr_offset);
257 // Encode the size of the terminal node info.256 // Encode the size of the terminal node info.
258 var size_buf: [@sizeOf(u64)]u8 = undefined;257 try bw.writeLeb128(bw.count - start);
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]);
265 } else {258 } else {
266 // Non-terminal node is delimited by 0 byte.259 // Non-terminal node is delimited by 0 byte.
267 try writer.writeByte(0);260 try bw.writeByte(0);
268 }261 }
269 // Write number of edges (max legal number of edges is 256).262 // Write number of edges (max legal number of edges is 255).
270 try writer.writeByte(@as(u8, @intCast(edges.items.len)));263 try bw.writeByte(@intCast(edges.items.len));
271264
272 for (edges.items) |edge_index| {265 for (edges.items) |edge_index| {
273 const edge = self.edges.items[edge_index];266 const edge = self.edges.items[edge_index];
274 // Write edge label and offset to next node in trie.267 // Write edge label and offset to next node in trie.
275 try writer.writeAll(edge.label);268 try bw.writeAll(edge.label);
276 try writer.writeByte(0);269 try bw.writeByte(0);
277 try leb.writeULEB128(writer, slice.items(.trie_offset)[edge.node]);270 try bw.writeLeb128(slice.items(.trie_offset)[edge.node]);
278 }271 }
279}272}
280273
...@@ -414,8 +407,10 @@ const macho = std.macho;...@@ -414,8 +407,10 @@ const macho = std.macho;
414const mem = std.mem;407const mem = std.mem;
415const std = @import("std");408const std = @import("std");
416const testing = std.testing;409const 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;
419const Allocator = mem.Allocator;414const Allocator = mem.Allocator;
420const MachO = @import("../../MachO.zig");415const MachO = @import("../../MachO.zig");
421const Trie = @This();416const Trie = @This();
src/link/MachO/dyld_info/bind.zig+155-187
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1pub const Entry = struct {1pub const Entry = struct {
2 target: MachO.Ref,2 target: MachO.Ref,
3 offset: u64,3 offset: u64,
4 segment_id: u8,4 segment_id: u4,
5 addend: i64,5 addend: i64,
66
7 pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool {7 pub fn lessThan(ctx: *MachO, entry: Entry, other: Entry) bool {
...@@ -20,14 +20,12 @@ pub const Bind = struct {...@@ -20,14 +20,12 @@ pub const Bind = struct {
20 entries: std.ArrayListUnmanaged(Entry) = .empty,20 entries: std.ArrayListUnmanaged(Entry) = .empty,
21 buffer: std.ArrayListUnmanaged(u8) = .empty,21 buffer: std.ArrayListUnmanaged(u8) = .empty,
2222
23 const Self = @This();23 pub fn deinit(bind: *Bind, gpa: Allocator) void {
2424 bind.entries.deinit(gpa);
25 pub fn deinit(self: *Self, gpa: Allocator) void {25 bind.buffer.deinit(gpa);
26 self.entries.deinit(gpa);
27 self.buffer.deinit(gpa);
28 }26 }
2927
30 pub fn updateSize(self: *Self, macho_file: *MachO) !void {28 pub fn updateSize(bind: *Bind, macho_file: *MachO) !void {
31 const tracy = trace(@src());29 const tracy = trace(@src());
32 defer tracy.end();30 defer tracy.end();
3331
...@@ -56,15 +54,12 @@ pub const Bind = struct {...@@ -56,15 +54,12 @@ pub const Bind = struct {
56 const addend = rel.addend + rel.getRelocAddend(cpu_arch);54 const addend = rel.addend + rel.getRelocAddend(cpu_arch);
57 const sym = rel.getTargetSymbol(atom.*, macho_file);55 const sym = rel.getTargetSymbol(atom.*, macho_file);
58 if (sym.isTlvInit(macho_file)) continue;56 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)).* = .{
60 .target = rel.getTargetSymbolRef(atom.*, macho_file),58 .target = rel.getTargetSymbolRef(atom.*, macho_file),
61 .offset = atom_addr + rel_offset - seg.vmaddr,59 .offset = atom_addr + rel_offset - seg.vmaddr,
62 .segment_id = seg_id,60 .segment_id = seg_id,
63 .addend = addend,61 .addend = addend,
64 };62 };
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 }
68 }63 }
69 }64 }
70 }65 }
...@@ -75,15 +70,12 @@ pub const Bind = struct {...@@ -75,15 +70,12 @@ pub const Bind = struct {
75 for (macho_file.got.symbols.items, 0..) |ref, idx| {70 for (macho_file.got.symbols.items, 0..) |ref, idx| {
76 const sym = ref.getSymbol(macho_file).?;71 const sym = ref.getSymbol(macho_file).?;
77 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);72 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)).* = .{
79 .target = ref,74 .target = ref,
80 .offset = addr - seg.vmaddr,75 .offset = addr - seg.vmaddr,
81 .segment_id = seg_id,76 .segment_id = seg_id,
82 .addend = 0,77 .addend = 0,
83 };78 };
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 }
87 }79 }
88 }80 }
8981
...@@ -94,15 +86,12 @@ pub const Bind = struct {...@@ -94,15 +86,12 @@ pub const Bind = struct {
94 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {86 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
95 const sym = ref.getSymbol(macho_file).?;87 const sym = ref.getSymbol(macho_file).?;
96 const addr = sect.addr + idx * @sizeOf(u64);88 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)).* = .{
98 .target = ref,90 .target = ref,
99 .offset = addr - seg.vmaddr,91 .offset = addr - seg.vmaddr,
100 .segment_id = seg_id,92 .segment_id = seg_id,
101 .addend = 0,93 .addend = 0,
102 };94 };
103 if (sym.flags.import and sym.flags.weak) {
104 try self.entries.append(gpa, bind_entry);
105 }
106 }95 }
107 }96 }
10897
...@@ -113,49 +102,48 @@ pub const Bind = struct {...@@ -113,49 +102,48 @@ pub const Bind = struct {
113 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {102 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
114 const sym = ref.getSymbol(macho_file).?;103 const sym = ref.getSymbol(macho_file).?;
115 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);104 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)).* = .{
117 .target = ref,106 .target = ref,
118 .offset = addr - seg.vmaddr,107 .offset = addr - seg.vmaddr,
119 .segment_id = seg_id,108 .segment_id = seg_id,
120 .addend = 0,109 .addend = 0,
121 };110 };
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 }
125 }111 }
126 }112 }
127113
128 try self.finalize(gpa, macho_file);114 try bind.finalize(gpa, macho_file);
129 macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));115 macho_file.dyld_info_cmd.bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
130 }116 }
131117
132 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {118 fn finalize(bind: *Bind, gpa: Allocator, ctx: *MachO) !void {
133 if (self.entries.items.len == 0) return;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
137 log.debug("bind opcodes", .{});125 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
141 var start: usize = 0;129 var start: usize = 0;
142 var seg_id: ?u8 = null;130 var seg_id: ?u8 = null;
143 for (self.entries.items, 0..) |entry, i| {131 for (bind.entries.items, 0..) |entry, i| {
144 if (seg_id != null and seg_id.? == entry.segment_id) continue;132 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);
146 seg_id = entry.segment_id;134 seg_id = entry.segment_id;
147 start = i;135 start = i;
148 }136 }
149137
150 try finalizeSegment(self.entries.items[start..], ctx, writer);138 try finalizeSegment(bind.entries.items[start..], ctx, bw);
151 try done(writer);139 try done(bw);
152 }140 }
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 {
155 if (entries.len == 0) return;143 if (entries.len == 0) return;
156144
157 const seg_id = entries[0].segment_id;145 const seg_id = entries[0].segment_id;
158 try setSegmentOffset(seg_id, 0, writer);146 try setSegmentOffset(seg_id, 0, bw);
159147
160 var offset: u64 = 0;148 var offset: u64 = 0;
161 var addend: i64 = 0;149 var addend: i64 = 0;
...@@ -175,15 +163,15 @@ pub const Bind = struct {...@@ -175,15 +163,15 @@ pub const Bind = struct {
175 if (target == null or !target.?.eql(current.target)) {163 if (target == null or !target.?.eql(current.target)) {
176 switch (state) {164 switch (state) {
177 .start => {},165 .start => {},
178 .bind_single => try doBind(writer),166 .bind_single => try doBind(bw),
179 .bind_times_skip => try doBindTimesSkip(count, skip, writer),167 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
180 }168 }
181 state = .start;169 state = .start;
182 target = current.target;170 target = current.target;
183171
184 const sym = current.target.getSymbol(ctx).?;172 const sym = current.target.getSymbol(ctx).?;
185 const name = sym.getName(ctx);173 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;
187 const ordinal: i16 = ord: {175 const ordinal: i16 = ord: {
188 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;176 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
189 if (sym.flags.import) {177 if (sym.flags.import) {
...@@ -195,13 +183,13 @@ pub const Bind = struct {...@@ -195,13 +183,13 @@ pub const Bind = struct {
195 break :ord macho.BIND_SPECIAL_DYLIB_SELF;183 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
196 };184 };
197185
198 try setSymbol(name, flags, writer);186 try setSymbol(name, flags, bw);
199 try setTypePointer(writer);187 try setTypePointer(bw);
200 try setDylibOrdinal(ordinal, writer);188 try setDylibOrdinal(ordinal, bw);
201189
202 if (current.addend != addend) {190 if (current.addend != addend) {
203 addend = current.addend;191 addend = current.addend;
204 try setAddend(addend, writer);192 try setAddend(addend, bw);
205 }193 }
206 }194 }
207195
...@@ -210,11 +198,11 @@ pub const Bind = struct {...@@ -210,11 +198,11 @@ pub const Bind = struct {
210 switch (state) {198 switch (state) {
211 .start => {199 .start => {
212 if (current.offset < offset) {200 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);
214 offset = offset - (offset - current.offset);202 offset = offset - (offset - current.offset);
215 } else if (current.offset > offset) {203 } else if (current.offset > offset) {
216 const delta = current.offset - offset;204 const delta = current.offset - offset;
217 try addAddr(delta, writer);205 try addAddr(delta, bw);
218 offset += delta;206 offset += delta;
219 }207 }
220 state = .bind_single;208 state = .bind_single;
...@@ -223,7 +211,7 @@ pub const Bind = struct {...@@ -223,7 +211,7 @@ pub const Bind = struct {
223 },211 },
224 .bind_single => {212 .bind_single => {
225 if (current.offset == offset) {213 if (current.offset == offset) {
226 try doBind(writer);214 try doBind(bw);
227 state = .start;215 state = .start;
228 } else if (current.offset > offset) {216 } else if (current.offset > offset) {
229 const delta = current.offset - offset;217 const delta = current.offset - offset;
...@@ -237,9 +225,9 @@ pub const Bind = struct {...@@ -237,9 +225,9 @@ pub const Bind = struct {
237 if (current.offset < offset) {225 if (current.offset < offset) {
238 count -= 1;226 count -= 1;
239 if (count == 1) {227 if (count == 1) {
240 try doBindAddAddr(skip, writer);228 try doBindAddAddr(skip, bw);
241 } else {229 } else {
242 try doBindTimesSkip(count, skip, writer);230 try doBindTimesSkip(count, skip, bw);
243 }231 }
244 state = .start;232 state = .start;
245 offset = offset - (@sizeOf(u64) + skip);233 offset = offset - (@sizeOf(u64) + skip);
...@@ -248,7 +236,7 @@ pub const Bind = struct {...@@ -248,7 +236,7 @@ pub const Bind = struct {
248 count += 1;236 count += 1;
249 offset += @sizeOf(u64) + skip;237 offset += @sizeOf(u64) + skip;
250 } else {238 } else {
251 try doBindTimesSkip(count, skip, writer);239 try doBindTimesSkip(count, skip, bw);
252 state = .start;240 state = .start;
253 i -= 1;241 i -= 1;
254 }242 }
...@@ -258,13 +246,13 @@ pub const Bind = struct {...@@ -258,13 +246,13 @@ pub const Bind = struct {
258246
259 switch (state) {247 switch (state) {
260 .start => unreachable,248 .start => unreachable,
261 .bind_single => try doBind(writer),249 .bind_single => try doBind(bw),
262 .bind_times_skip => try doBindTimesSkip(count, skip, writer),250 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
263 }251 }
264 }252 }
265253
266 pub fn write(self: Self, writer: anytype) !void {254 pub fn write(bind: Bind, bw: *Writer) Writer.Error!void {
267 try writer.writeAll(self.buffer.items);255 try bw.writeAll(bind.buffer.items);
268 }256 }
269};257};
270258
...@@ -272,14 +260,12 @@ pub const WeakBind = struct {...@@ -272,14 +260,12 @@ pub const WeakBind = struct {
272 entries: std.ArrayListUnmanaged(Entry) = .empty,260 entries: std.ArrayListUnmanaged(Entry) = .empty,
273 buffer: std.ArrayListUnmanaged(u8) = .empty,261 buffer: std.ArrayListUnmanaged(u8) = .empty,
274262
275 const Self = @This();263 pub fn deinit(bind: *WeakBind, gpa: Allocator) void {
276264 bind.entries.deinit(gpa);
277 pub fn deinit(self: *Self, gpa: Allocator) void {265 bind.buffer.deinit(gpa);
278 self.entries.deinit(gpa);
279 self.buffer.deinit(gpa);
280 }266 }
281267
282 pub fn updateSize(self: *Self, macho_file: *MachO) !void {268 pub fn updateSize(bind: *WeakBind, macho_file: *MachO) !void {
283 const tracy = trace(@src());269 const tracy = trace(@src());
284 defer tracy.end();270 defer tracy.end();
285271
...@@ -308,15 +294,12 @@ pub const WeakBind = struct {...@@ -308,15 +294,12 @@ pub const WeakBind = struct {
308 const addend = rel.addend + rel.getRelocAddend(cpu_arch);294 const addend = rel.addend + rel.getRelocAddend(cpu_arch);
309 const sym = rel.getTargetSymbol(atom.*, macho_file);295 const sym = rel.getTargetSymbol(atom.*, macho_file);
310 if (sym.isTlvInit(macho_file)) continue;296 if (sym.isTlvInit(macho_file)) continue;
311 const entry = Entry{297 if (!sym.isLocal() and sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
312 .target = rel.getTargetSymbolRef(atom.*, macho_file),298 .target = rel.getTargetSymbolRef(atom.*, macho_file),
313 .offset = atom_addr + rel_offset - seg.vmaddr,299 .offset = atom_addr + rel_offset - seg.vmaddr,
314 .segment_id = seg_id,300 .segment_id = seg_id,
315 .addend = addend,301 .addend = addend,
316 };302 };
317 if (!sym.isLocal() and sym.flags.weak) {
318 try self.entries.append(gpa, entry);
319 }
320 }303 }
321 }304 }
322 }305 }
...@@ -327,15 +310,12 @@ pub const WeakBind = struct {...@@ -327,15 +310,12 @@ pub const WeakBind = struct {
327 for (macho_file.got.symbols.items, 0..) |ref, idx| {310 for (macho_file.got.symbols.items, 0..) |ref, idx| {
328 const sym = ref.getSymbol(macho_file).?;311 const sym = ref.getSymbol(macho_file).?;
329 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);312 const addr = macho_file.got.getAddress(@intCast(idx), macho_file);
330 const entry = Entry{313 if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
331 .target = ref,314 .target = ref,
332 .offset = addr - seg.vmaddr,315 .offset = addr - seg.vmaddr,
333 .segment_id = seg_id,316 .segment_id = seg_id,
334 .addend = 0,317 .addend = 0,
335 };318 };
336 if (sym.flags.weak) {
337 try self.entries.append(gpa, entry);
338 }
339 }319 }
340 }320 }
341321
...@@ -347,15 +327,12 @@ pub const WeakBind = struct {...@@ -347,15 +327,12 @@ pub const WeakBind = struct {
347 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {327 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
348 const sym = ref.getSymbol(macho_file).?;328 const sym = ref.getSymbol(macho_file).?;
349 const addr = sect.addr + idx * @sizeOf(u64);329 const addr = sect.addr + idx * @sizeOf(u64);
350 const bind_entry = Entry{330 if (sym.flags.weak) (try bind.entries.addOne(gpa)).* = .{
351 .target = ref,331 .target = ref,
352 .offset = addr - seg.vmaddr,332 .offset = addr - seg.vmaddr,
353 .segment_id = seg_id,333 .segment_id = seg_id,
354 .addend = 0,334 .addend = 0,
355 };335 };
356 if (sym.flags.weak) {
357 try self.entries.append(gpa, bind_entry);
358 }
359 }336 }
360 }337 }
361338
...@@ -366,49 +343,48 @@ pub const WeakBind = struct {...@@ -366,49 +343,48 @@ pub const WeakBind = struct {
366 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {343 for (macho_file.tlv_ptr.symbols.items, 0..) |ref, idx| {
367 const sym = ref.getSymbol(macho_file).?;344 const sym = ref.getSymbol(macho_file).?;
368 const addr = macho_file.tlv_ptr.getAddress(@intCast(idx), macho_file);345 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)).* = .{
370 .target = ref,347 .target = ref,
371 .offset = addr - seg.vmaddr,348 .offset = addr - seg.vmaddr,
372 .segment_id = seg_id,349 .segment_id = seg_id,
373 .addend = 0,350 .addend = 0,
374 };351 };
375 if (sym.flags.weak) {
376 try self.entries.append(gpa, entry);
377 }
378 }352 }
379 }353 }
380354
381 try self.finalize(gpa, macho_file);355 try bind.finalize(gpa, macho_file);
382 macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));356 macho_file.dyld_info_cmd.weak_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
383 }357 }
384358
385 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {359 fn finalize(bind: *WeakBind, gpa: Allocator, ctx: *MachO) !void {
386 if (self.entries.items.len == 0) return;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
390 log.debug("weak bind opcodes", .{});366 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
394 var start: usize = 0;370 var start: usize = 0;
395 var seg_id: ?u8 = null;371 var seg_id: ?u8 = null;
396 for (self.entries.items, 0..) |entry, i| {372 for (bind.entries.items, 0..) |entry, i| {
397 if (seg_id != null and seg_id.? == entry.segment_id) continue;373 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);
399 seg_id = entry.segment_id;375 seg_id = entry.segment_id;
400 start = i;376 start = i;
401 }377 }
402378
403 try finalizeSegment(self.entries.items[start..], ctx, writer);379 try finalizeSegment(bind.entries.items[start..], ctx, bw);
404 try done(writer);380 try done(bw);
405 }381 }
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 {
408 if (entries.len == 0) return;384 if (entries.len == 0) return;
409385
410 const seg_id = entries[0].segment_id;386 const seg_id = entries[0].segment_id;
411 try setSegmentOffset(seg_id, 0, writer);387 try setSegmentOffset(seg_id, 0, bw);
412388
413 var offset: u64 = 0;389 var offset: u64 = 0;
414 var addend: i64 = 0;390 var addend: i64 = 0;
...@@ -428,8 +404,8 @@ pub const WeakBind = struct {...@@ -428,8 +404,8 @@ pub const WeakBind = struct {
428 if (target == null or !target.?.eql(current.target)) {404 if (target == null or !target.?.eql(current.target)) {
429 switch (state) {405 switch (state) {
430 .start => {},406 .start => {},
431 .bind_single => try doBind(writer),407 .bind_single => try doBind(bw),
432 .bind_times_skip => try doBindTimesSkip(count, skip, writer),408 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
433 }409 }
434 state = .start;410 state = .start;
435 target = current.target;411 target = current.target;
...@@ -438,12 +414,12 @@ pub const WeakBind = struct {...@@ -438,12 +414,12 @@ pub const WeakBind = struct {
438 const name = sym.getName(ctx);414 const name = sym.getName(ctx);
439 const flags: u8 = 0; // TODO NON_WEAK_DEFINITION415 const flags: u8 = 0; // TODO NON_WEAK_DEFINITION
440416
441 try setSymbol(name, flags, writer);417 try setSymbol(name, flags, bw);
442 try setTypePointer(writer);418 try setTypePointer(bw);
443419
444 if (current.addend != addend) {420 if (current.addend != addend) {
445 addend = current.addend;421 addend = current.addend;
446 try setAddend(addend, writer);422 try setAddend(addend, bw);
447 }423 }
448 }424 }
449425
...@@ -452,11 +428,11 @@ pub const WeakBind = struct {...@@ -452,11 +428,11 @@ pub const WeakBind = struct {
452 switch (state) {428 switch (state) {
453 .start => {429 .start => {
454 if (current.offset < offset) {430 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);
456 offset = offset - (offset - current.offset);432 offset = offset - (offset - current.offset);
457 } else if (current.offset > offset) {433 } else if (current.offset > offset) {
458 const delta = current.offset - offset;434 const delta = current.offset - offset;
459 try addAddr(delta, writer);435 try addAddr(delta, bw);
460 offset += delta;436 offset += delta;
461 }437 }
462 state = .bind_single;438 state = .bind_single;
...@@ -465,7 +441,7 @@ pub const WeakBind = struct {...@@ -465,7 +441,7 @@ pub const WeakBind = struct {
465 },441 },
466 .bind_single => {442 .bind_single => {
467 if (current.offset == offset) {443 if (current.offset == offset) {
468 try doBind(writer);444 try doBind(bw);
469 state = .start;445 state = .start;
470 } else if (current.offset > offset) {446 } else if (current.offset > offset) {
471 const delta = current.offset - offset;447 const delta = current.offset - offset;
...@@ -479,9 +455,9 @@ pub const WeakBind = struct {...@@ -479,9 +455,9 @@ pub const WeakBind = struct {
479 if (current.offset < offset) {455 if (current.offset < offset) {
480 count -= 1;456 count -= 1;
481 if (count == 1) {457 if (count == 1) {
482 try doBindAddAddr(skip, writer);458 try doBindAddAddr(skip, bw);
483 } else {459 } else {
484 try doBindTimesSkip(count, skip, writer);460 try doBindTimesSkip(count, skip, bw);
485 }461 }
486 state = .start;462 state = .start;
487 offset = offset - (@sizeOf(u64) + skip);463 offset = offset - (@sizeOf(u64) + skip);
...@@ -490,7 +466,7 @@ pub const WeakBind = struct {...@@ -490,7 +466,7 @@ pub const WeakBind = struct {
490 count += 1;466 count += 1;
491 offset += @sizeOf(u64) + skip;467 offset += @sizeOf(u64) + skip;
492 } else {468 } else {
493 try doBindTimesSkip(count, skip, writer);469 try doBindTimesSkip(count, skip, bw);
494 state = .start;470 state = .start;
495 i -= 1;471 i -= 1;
496 }472 }
...@@ -500,13 +476,13 @@ pub const WeakBind = struct {...@@ -500,13 +476,13 @@ pub const WeakBind = struct {
500476
501 switch (state) {477 switch (state) {
502 .start => unreachable,478 .start => unreachable,
503 .bind_single => try doBind(writer),479 .bind_single => try doBind(bw),
504 .bind_times_skip => try doBindTimesSkip(count, skip, writer),480 .bind_times_skip => try doBindTimesSkip(count, skip, bw),
505 }481 }
506 }482 }
507483
508 pub fn write(self: Self, writer: anytype) !void {484 pub fn write(bind: WeakBind, bw: *Writer) Writer.Error!void {
509 try writer.writeAll(self.buffer.items);485 try bw.writeAll(bind.buffer.items);
510 }486 }
511};487};
512488
...@@ -515,15 +491,13 @@ pub const LazyBind = struct {...@@ -515,15 +491,13 @@ pub const LazyBind = struct {
515 buffer: std.ArrayListUnmanaged(u8) = .empty,491 buffer: std.ArrayListUnmanaged(u8) = .empty,
516 offsets: std.ArrayListUnmanaged(u32) = .empty,492 offsets: std.ArrayListUnmanaged(u32) = .empty,
517493
518 const Self = @This();494 pub fn deinit(bind: *LazyBind, gpa: Allocator) void {
519495 bind.entries.deinit(gpa);
520 pub fn deinit(self: *Self, gpa: Allocator) void {496 bind.buffer.deinit(gpa);
521 self.entries.deinit(gpa);497 bind.offsets.deinit(gpa);
522 self.buffer.deinit(gpa);
523 self.offsets.deinit(gpa);
524 }498 }
525499
526 pub fn updateSize(self: *Self, macho_file: *MachO) !void {500 pub fn updateSize(bind: *LazyBind, macho_file: *MachO) !void {
527 const tracy = trace(@src());501 const tracy = trace(@src());
528 defer tracy.end();502 defer tracy.end();
529503
...@@ -537,36 +511,35 @@ pub const LazyBind = struct {...@@ -537,36 +511,35 @@ pub const LazyBind = struct {
537 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {511 for (macho_file.stubs.symbols.items, 0..) |ref, idx| {
538 const sym = ref.getSymbol(macho_file).?;512 const sym = ref.getSymbol(macho_file).?;
539 const addr = sect.addr + idx * @sizeOf(u64);513 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)).* = .{
541 .target = ref,515 .target = ref,
542 .offset = addr - seg.vmaddr,516 .offset = addr - seg.vmaddr,
543 .segment_id = seg_id,517 .segment_id = seg_id,
544 .addend = 0,518 .addend = 0,
545 };519 };
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 }
549 }520 }
550521
551 try self.finalize(gpa, macho_file);522 try bind.finalize(gpa, macho_file);
552 macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(self.buffer.items.len), @alignOf(u64));523 macho_file.dyld_info_cmd.lazy_bind_size = mem.alignForward(u32, @intCast(bind.buffer.items.len), @alignOf(u64));
553 }524 }
554525
555 fn finalize(self: *Self, gpa: Allocator, ctx: *MachO) !void {526 fn finalize(bind: *LazyBind, gpa: Allocator, ctx: *MachO) !void {
556 try self.offsets.ensureTotalCapacityPrecise(gpa, self.entries.items.len);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
560 log.debug("lazy bind opcodes", .{});533 log.debug("lazy bind opcodes", .{});
561534
562 var addend: i64 = 0;535 var addend: i64 = 0;
563536
564 for (self.entries.items) |entry| {537 for (bind.entries.items) |entry| {
565 self.offsets.appendAssumeCapacity(@intCast(self.buffer.items.len));538 bind.offsets.appendAssumeCapacity(@intCast(bind.buffer.items.len));
566539
567 const sym = entry.target.getSymbol(ctx).?;540 const sym = entry.target.getSymbol(ctx).?;
568 const name = sym.getName(ctx);541 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;
570 const ordinal: i16 = ord: {543 const ordinal: i16 = ord: {
571 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;544 if (sym.flags.interposable) break :ord macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP;
572 if (sym.flags.import) {545 if (sym.flags.import) {
...@@ -578,121 +551,116 @@ pub const LazyBind = struct {...@@ -578,121 +551,116 @@ pub const LazyBind = struct {
578 break :ord macho.BIND_SPECIAL_DYLIB_SELF;551 break :ord macho.BIND_SPECIAL_DYLIB_SELF;
579 };552 };
580553
581 try setSegmentOffset(entry.segment_id, entry.offset, writer);554 try setSegmentOffset(entry.segment_id, entry.offset, bw);
582 try setSymbol(name, flags, writer);555 try setSymbol(name, flags, bw);
583 try setDylibOrdinal(ordinal, writer);556 try setDylibOrdinal(ordinal, bw);
584557
585 if (entry.addend != addend) {558 if (entry.addend != addend) {
586 try setAddend(entry.addend, writer);559 try setAddend(entry.addend, bw);
587 addend = entry.addend;560 addend = entry.addend;
588 }561 }
589562
590 try doBind(writer);563 try doBind(bw);
591 try done(writer);564 try done(bw);
592 }565 }
593 }566 }
594567
595 pub fn write(self: Self, writer: anytype) !void {568 pub fn write(bind: LazyBind, bw: *Writer) Writer.Error!void {
596 try writer.writeAll(self.buffer.items);569 try bw.writeAll(bind.buffer.items);
597 }570 }
598};571};
599572
600fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void {573fn setSegmentOffset(segment_id: u4, offset: u64, bw: *Writer) Writer.Error!void {
601 log.debug(">>> set segment: {d} and offset: {x}", .{ segment_id, offset });574 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)));575 try bw.writeByte(macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | segment_id);
603 try std.leb.writeUleb128(writer, offset);576 try bw.writeLeb128(offset);
604}577}
605578
606fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void {579fn setSymbol(name: []const u8, flags: u4, bw: *Writer) Writer.Error!void {
607 log.debug(">>> set symbol: {s} with flags: {x}", .{ name, flags });580 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)));581 try bw.writeByte(macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags);
609 try writer.writeAll(name);582 try bw.writeAll(name);
610 try writer.writeByte(0);583 try bw.writeByte(0);
611}584}
612585
613fn setTypePointer(writer: anytype) !void {586fn setTypePointer(bw: *Writer) Writer.Error!void {
614 log.debug(">>> set type: {d}", .{macho.BIND_TYPE_POINTER});587 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)));
616}589}
617590
618fn setDylibOrdinal(ordinal: i16, writer: anytype) !void {591fn setDylibOrdinal(ordinal: i16, bw: *Writer) Writer.Error!void {
619 if (ordinal <= 0) {592 switch (ordinal) {
620 switch (ordinal) {593 else => unreachable, // Invalid dylib special binding
621 macho.BIND_SPECIAL_DYLIB_SELF,594 macho.BIND_SPECIAL_DYLIB_SELF,
622 macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE,595 macho.BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE,
623 macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP,596 macho.BIND_SPECIAL_DYLIB_FLAT_LOOKUP,
624 => {},597 => {
625 else => unreachable, // Invalid dylib special binding598 log.debug(">>> set dylib special: {d}", .{ordinal});
626 }599 try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @bitCast(@as(i4, @intCast(ordinal)))));
627 log.debug(">>> set dylib special: {d}", .{ordinal});600 },
628 const cast = @as(u16, @bitCast(ordinal));601 1...std.math.maxInt(i16) => {
629 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | @as(u4, @truncate(cast)));602 log.debug(">>> set dylib ordinal: {d}", .{ordinal});
630 } else {603 if (std.math.cast(u4, ordinal)) |imm| {
631 const cast = @as(u16, @bitCast(ordinal));604 try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | imm);
632 log.debug(">>> set dylib ordinal: {d}", .{ordinal});605 } else {
633 if (cast <= 0xf) {606 try bw.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
634 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | @as(u4, @truncate(cast)));607 try bw.writeUleb128(ordinal);
635 } else {608 }
636 try writer.writeByte(macho.BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);609 },
637 try std.leb.writeUleb128(writer, cast);
638 }
639 }610 }
640}611}
641612
642fn setAddend(addend: i64, writer: anytype) !void {613fn setAddend(addend: i64, bw: *Writer) Writer.Error!void {
643 log.debug(">>> set addend: {x}", .{addend});614 log.debug(">>> set addend: {x}", .{addend});
644 try writer.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);615 try bw.writeByte(macho.BIND_OPCODE_SET_ADDEND_SLEB);
645 try std.leb.writeIleb128(writer, addend);616 try bw.writeLeb128(addend);
646}617}
647618
648fn doBind(writer: anytype) !void {619fn doBind(bw: *Writer) Writer.Error!void {
649 log.debug(">>> bind", .{});620 log.debug(">>> bind", .{});
650 try writer.writeByte(macho.BIND_OPCODE_DO_BIND);621 try bw.writeByte(macho.BIND_OPCODE_DO_BIND);
651}622}
652623
653fn doBindAddAddr(addr: u64, writer: anytype) !void {624fn doBindAddAddr(addr: u64, bw: *Writer) Writer.Error!void {
654 log.debug(">>> bind with add: {x}", .{addr});625 log.debug(">>> bind with add: {x}", .{addr});
655 if (std.mem.isAlignedGeneric(u64, addr, @sizeOf(u64))) {626 if (std.math.divExact(u64, addr, @sizeOf(u64))) |scaled| {
656 const imm = @divExact(addr, @sizeOf(u64));627 if (std.math.cast(u4, scaled)) |imm_scaled| return bw.writeByte(
657 if (imm <= 0xf) {628 macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | imm_scaled,
658 try writer.writeByte(629 );
659 macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | @as(u4, @truncate(imm)),630 } else |_| {}
660 );631 try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
661 return;632 try bw.writeLeb128(addr);
662 }
663 }
664 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
665 try std.leb.writeUleb128(writer, addr);
666}633}
667634
668fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void {635fn doBindTimesSkip(count: usize, skip: u64, bw: *Writer) Writer.Error!void {
669 log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });636 log.debug(">>> bind with count: {d} and skip: {x}", .{ count, skip });
670 try writer.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);637 try bw.writeByte(macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
671 try std.leb.writeUleb128(writer, count);638 try bw.writeLeb128(count);
672 try std.leb.writeUleb128(writer, skip);639 try bw.writeLeb128(skip);
673}640}
674641
675fn addAddr(addr: u64, writer: anytype) !void {642fn addAddr(addr: u64, bw: *Writer) Writer.Error!void {
676 log.debug(">>> add: {x}", .{addr});643 log.debug(">>> add: {x}", .{addr});
677 try writer.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);644 try bw.writeByte(macho.BIND_OPCODE_ADD_ADDR_ULEB);
678 try std.leb.writeUleb128(writer, addr);645 try bw.writeLeb128(addr);
679}646}
680647
681fn done(writer: anytype) !void {648fn done(bw: *Writer) Writer.Error!void {
682 log.debug(">>> done", .{});649 log.debug(">>> done", .{});
683 try writer.writeByte(macho.BIND_OPCODE_DONE);650 try bw.writeByte(macho.BIND_OPCODE_DONE);
684}651}
685652
653const std = @import("std");
686const assert = std.debug.assert;654const assert = std.debug.assert;
687const leb = std.leb;655const leb = std.leb;
688const log = std.log.scoped(.link_dyld_info);656const log = std.log.scoped(.link_dyld_info);
689const macho = std.macho;657const macho = std.macho;
690const mem = std.mem;658const mem = std.mem;
691const testing = std.testing;659const testing = std.testing;
692const trace = @import("../../../tracy.zig").trace;660const Allocator = std.mem.Allocator;
693const std = @import("std");661const Writer = std.io.Writer;
694662
695const Allocator = mem.Allocator;663const trace = @import("../../../tracy.zig").trace;
696const File = @import("../file.zig").File;664const File = @import("../file.zig").File;
697const MachO = @import("../../MachO.zig");665const MachO = @import("../../MachO.zig");
698const Symbol = @import("../Symbol.zig");666const Symbol = @import("../Symbol.zig");
src/link/MachO/eh_frame.zig+56-100
...@@ -12,36 +12,33 @@ pub const Cie = struct {...@@ -12,36 +12,33 @@ pub const Cie = struct {
12 const tracy = trace(@src());12 const tracy = trace(@src());
13 defer tracy.end();13 defer tracy.end();
1414
15 const data = cie.getData(macho_file);15 var r: std.io.Reader = .fixed(cie.getData(macho_file));
16 const aug = std.mem.sliceTo(@as([*:0]const u8, @ptrCast(data.ptr + 9)), 0);
1716
17 try r.discard(9);
18 const aug = try r.takeSentinel(0);
18 if (aug[0] != 'z') return; // TODO should we error out?19 if (aug[0] != 'z') return; // TODO should we error out?
1920
20 var stream = std.io.fixedBufferStream(data[9 + aug.len + 1 ..]);21 _ = try r.takeLeb128(u64); // code alignment factor
21 var creader = std.io.countingReader(stream.reader());22 _ = try r.takeLeb128(u64); // data alignment factor
22 const reader = creader.reader();23 _ = try r.takeLeb128(u64); // return address register
2324 _ = try r.takeLeb128(u64); // augmentation data length
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
2825
29 for (aug[1..]) |ch| switch (ch) {26 for (aug[1..]) |ch| switch (ch) {
30 'R' => {27 'R' => {
31 const enc = try reader.readByte();28 const enc = try r.takeByte();
32 if (enc != DW_EH_PE.pcrel | DW_EH_PE.absptr) {29 if (enc != DW_EH_PE.pcrel | DW_EH_PE.absptr) {
33 @panic("unexpected pointer encoding"); // TODO error30 @panic("unexpected pointer encoding"); // TODO error
34 }31 }
35 },32 },
36 'P' => {33 'P' => {
37 const enc = try reader.readByte();34 const enc = try r.takeByte();
38 if (enc != DW_EH_PE.pcrel | DW_EH_PE.indirect | DW_EH_PE.sdata4) {35 if (enc != DW_EH_PE.pcrel | DW_EH_PE.indirect | DW_EH_PE.sdata4) {
39 @panic("unexpected personality pointer encoding"); // TODO error36 @panic("unexpected personality pointer encoding"); // TODO error
40 }37 }
41 _ = try reader.readInt(u32, .little); // personality pointer38 _ = try r.takeInt(u32, .little); // personality pointer
42 },39 },
43 'L' => {40 'L' => {
44 const enc = try reader.readByte();41 const enc = try r.takeByte();
45 switch (enc & DW_EH_PE.type_mask) {42 switch (enc & DW_EH_PE.type_mask) {
46 DW_EH_PE.sdata4 => cie.lsda_size = .p32,43 DW_EH_PE.sdata4 => cie.lsda_size = .p32,
47 DW_EH_PE.absptr => cie.lsda_size = .p64,44 DW_EH_PE.absptr => cie.lsda_size = .p64,
...@@ -81,46 +78,26 @@ pub const Cie = struct {...@@ -81,46 +78,26 @@ pub const Cie = struct {
81 return true;78 return true;
82 }79 }
8380
84 pub fn format(81 pub fn fmt(cie: Cie, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
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) {
98 return .{ .data = .{82 return .{ .data = .{
99 .cie = cie,83 .cie = cie,
100 .macho_file = macho_file,84 .macho_file = macho_file,
101 } };85 } };
102 }86 }
10387
104 const FormatContext = struct {88 const Format = struct {
105 cie: Cie,89 cie: Cie,
106 macho_file: *MachO,90 macho_file: *MachO,
107 };
10891
109 fn format2(92 fn default(f: Format, w: *Writer) Writer.Error!void {
110 ctx: FormatContext,93 const cie = f.cie;
111 comptime unused_fmt_string: []const u8,94 try w.print("@{x} : size({x})", .{
112 options: std.fmt.FormatOptions,95 cie.offset,
113 writer: anytype,96 cie.getSize(),
114 ) !void {97 });
115 _ = unused_fmt_string;98 if (!cie.alive) try w.writeAll(" : [*]");
116 _ = options;99 }
117 const cie = ctx.cie;100 };
118 try writer.print("@{x} : size({x})", .{
119 cie.offset,
120 cie.getSize(),
121 });
122 if (!cie.alive) try writer.writeAll(" : [*]");
123 }
124101
125 pub const Index = u32;102 pub const Index = u32;
126103
...@@ -148,12 +125,16 @@ pub const Fde = struct {...@@ -148,12 +125,16 @@ pub const Fde = struct {
148 const tracy = trace(@src());125 const tracy = trace(@src());
149 defer tracy.end();126 defer tracy.end();
150127
151 const data = fde.getData(macho_file);
152 const object = fde.getObject(macho_file);128 const object = fde.getObject(macho_file);
153 const sect = object.sections.items(.header)[object.eh_frame_sect_index.?];129 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
155 // Parse target atom index137 // Parse target atom index
156 const pc_begin = std.mem.readInt(i64, data[8..][0..8], .little);
157 const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);138 const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
158 fde.atom = object.findAtom(taddr) orelse {139 fde.atom = object.findAtom(taddr) orelse {
159 try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{140 try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
...@@ -165,7 +146,6 @@ pub const Fde = struct {...@@ -165,7 +146,6 @@ pub const Fde = struct {
165 fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));146 fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
166147
167 // Associate with a CIE148 // Associate with a CIE
168 const cie_ptr = std.mem.readInt(u32, data[4..8], .little);
169 const cie_offset = fde.offset + 4 - cie_ptr;149 const cie_offset = fde.offset + 4 - cie_ptr;
170 const cie_index = for (object.cies.items, 0..) |cie, cie_index| {150 const cie_index = for (object.cies.items, 0..) |cie, cie_index| {
171 if (cie.offset == cie_offset) break @as(Cie.Index, @intCast(cie_index));151 if (cie.offset == cie_offset) break @as(Cie.Index, @intCast(cie_index));
...@@ -183,14 +163,12 @@ pub const Fde = struct {...@@ -183,14 +163,12 @@ pub const Fde = struct {
183163
184 // Parse LSDA atom index if any164 // Parse LSDA atom index if any
185 if (cie.lsda_size) |lsda_size| {165 if (cie.lsda_size) |lsda_size| {
186 var stream = std.io.fixedBufferStream(data[24..]);166 try br.discard(8);
187 var creader = std.io.countingReader(stream.reader());167 _ = try br.takeLeb128(u64); // augmentation length
188 const reader = creader.reader();168 fde.lsda_ptr_offset = @intCast(br.seek);
189 _ = try leb.readUleb128(u64, reader); // augmentation length
190 fde.lsda_ptr_offset = @intCast(creader.bytes_read + 24);
191 const lsda_ptr = switch (lsda_size) {169 const lsda_ptr = switch (lsda_size) {
192 .p32 => try reader.readInt(i32, .little),170 .p32 => try br.takeInt(i32, .little),
193 .p64 => try reader.readInt(i64, .little),171 .p64 => try br.takeInt(i64, .little),
194 };172 };
195 const lsda_addr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + fde.lsda_ptr_offset)) + lsda_ptr);173 const lsda_addr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + fde.lsda_ptr_offset)) + lsda_ptr);
196 fde.lsda = object.findAtom(lsda_addr) orelse {174 fde.lsda = object.findAtom(lsda_addr) orelse {
...@@ -231,56 +209,35 @@ pub const Fde = struct {...@@ -231,56 +209,35 @@ pub const Fde = struct {
231 return fde.getObject(macho_file).getAtom(fde.lsda);209 return fde.getObject(macho_file).getAtom(fde.lsda);
232 }210 }
233211
234 pub fn format(212 pub fn fmt(fde: Fde, macho_file: *MachO) std.fmt.Formatter(Format, Format.default) {
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) {
248 return .{ .data = .{213 return .{ .data = .{
249 .fde = fde,214 .fde = fde,
250 .macho_file = macho_file,215 .macho_file = macho_file,
251 } };216 } };
252 }217 }
253218
254 const FormatContext = struct {219 const Format = struct {
255 fde: Fde,220 fde: Fde,
256 macho_file: *MachO,221 macho_file: *MachO,
257 };
258222
259 fn format2(223 fn default(f: Format, w: *Writer) Writer.Error!void {
260 ctx: FormatContext,224 const fde = f.fde;
261 comptime unused_fmt_string: []const u8,225 const macho_file = f.macho_file;
262 options: std.fmt.FormatOptions,226 try w.print("@{x} : size({x}) : cie({d}) : {s}", .{
263 writer: anytype,227 fde.offset,
264 ) !void {228 fde.getSize(),
265 _ = unused_fmt_string;229 fde.cie,
266 _ = options;230 fde.getAtom(macho_file).getName(macho_file),
267 const fde = ctx.fde;231 });
268 const macho_file = ctx.macho_file;232 if (!fde.alive) try w.writeAll(" : [*]");
269 try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{233 }
270 fde.offset,234 };
271 fde.getSize(),
272 fde.cie,
273 fde.getAtom(macho_file).getName(macho_file),
274 });
275 if (!fde.alive) try writer.writeAll(" : [*]");
276 }
277235
278 pub const Index = u32;236 pub const Index = u32;
279};237};
280238
281pub const Iterator = struct {239pub const Iterator = struct {
282 data: []const u8,240 reader: *std.io.Reader,
283 pos: u32 = 0,
284241
285 pub const Record = struct {242 pub const Record = struct {
286 tag: enum { fde, cie },243 tag: enum { fde, cie },
...@@ -289,21 +246,19 @@ pub const Iterator = struct {...@@ -289,21 +246,19 @@ pub const Iterator = struct {
289 };246 };
290247
291 pub fn next(it: *Iterator) !?Record {248 pub fn next(it: *Iterator) !?Record {
292 if (it.pos >= it.data.len) return null;249 const r = it.reader;
293250 if (r.seek >= r.storageBuffer().len) return null;
294 var stream = std.io.fixedBufferStream(it.data[it.pos..]);
295 const reader = stream.reader();
296251
297 const size = try reader.readInt(u32, .little);252 const size = try r.takeInt(u32, .little);
298 if (size == 0xFFFFFFFF) @panic("DWARF CFI is 32bit on macOS");253 if (size == 0xFFFFFFFF) @panic("DWARF CFI is 32bit on macOS");
299254
300 const id = try reader.readInt(u32, .little);255 const id = try r.takeInt(u32, .little);
301 const record = Record{256 const record: Record = .{
302 .tag = if (id == 0) .cie else .fde,257 .tag = if (id == 0) .cie else .fde,
303 .offset = it.pos,258 .offset = @intCast(r.seek),
304 .size = size,259 .size = size,
305 };260 };
306 it.pos += size + 4;261 try r.discard(size);
307262
308 return record;263 return record;
309 }264 }
...@@ -545,6 +500,7 @@ const math = std.math;...@@ -545,6 +500,7 @@ const math = std.math;
545const mem = std.mem;500const mem = std.mem;
546const std = @import("std");501const std = @import("std");
547const trace = @import("../../tracy.zig").trace;502const trace = @import("../../tracy.zig").trace;
503const Writer = std.io.Writer;
548504
549const Allocator = std.mem.Allocator;505const Allocator = std.mem.Allocator;
550const Atom = @import("Atom.zig");506const Atom = @import("Atom.zig");
src/link/MachO/file.zig+9-8
...@@ -14,12 +14,12 @@ pub const File = union(enum) {...@@ -14,12 +14,12 @@ pub const File = union(enum) {
14 return .{ .data = file };14 return .{ .data = file };
15 }15 }
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 {
18 switch (file) {18 switch (file) {
19 .zig_object => |zo| try writer.writeAll(zo.basename),19 .zig_object => |zo| try w.writeAll(zo.basename),
20 .internal => try writer.writeAll("internal"),20 .internal => try w.writeAll("internal"),
21 .object => |x| try writer.print("{}", .{x.fmtPath()}),21 .object => |x| try w.print("{f}", .{x.fmtPath()}),
22 .dylib => |dl| try writer.print("{}", .{@as(Path, dl.path)}),22 .dylib => |dl| try w.print("{f}", .{@as(Path, dl.path)}),
23 }23 }
24 }24 }
2525
...@@ -321,11 +321,11 @@ pub const File = union(enum) {...@@ -321,11 +321,11 @@ pub const File = union(enum) {
321 };321 };
322 }322 }
323323
324 pub fn writeAr(file: File, 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 {
325 return switch (file) {325 return switch (file) {
326 .dylib, .internal => unreachable,326 .dylib, .internal => unreachable,
327 .zig_object => |x| x.writeAr(ar_format, writer),327 .zig_object => |x| x.writeAr(bw, ar_format),
328 .object => |x| x.writeAr(ar_format, macho_file, writer),328 .object => |x| x.writeAr(bw, ar_format, macho_file),
329 };329 };
330 }330 }
331331
...@@ -364,6 +364,7 @@ const log = std.log.scoped(.link);...@@ -364,6 +364,7 @@ const log = std.log.scoped(.link);
364const macho = std.macho;364const macho = std.macho;
365const Allocator = std.mem.Allocator;365const Allocator = std.mem.Allocator;
366const Path = std.Build.Cache.Path;366const Path = std.Build.Cache.Path;
367const Writer = std.io.Writer;
367368
368const trace = @import("../../tracy.zig").trace;369const trace = @import("../../tracy.zig").trace;
369const Archive = @import("Archive.zig");370const Archive = @import("Archive.zig");
src/link/MachO/load_commands.zig+22-30
...@@ -3,6 +3,7 @@ const assert = std.debug.assert;...@@ -3,6 +3,7 @@ const assert = std.debug.assert;
3const log = std.log.scoped(.link);3const log = std.log.scoped(.link);
4const macho = std.macho;4const macho = std.macho;
5const mem = std.mem;5const mem = std.mem;
6const Writer = std.io.Writer;
67
7const Allocator = mem.Allocator;8const Allocator = mem.Allocator;
8const DebugSymbols = @import("DebugSymbols.zig");9const DebugSymbols = @import("DebugSymbols.zig");
...@@ -180,23 +181,20 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {...@@ -180,23 +181,20 @@ pub fn calcMinHeaderPadSize(macho_file: *MachO) !u32 {
180 return offset;181 return offset;
181}182}
182183
183pub fn writeDylinkerLC(writer: anytype) !void {184pub fn writeDylinkerLC(bw: *Writer) Writer.Error!void {
184 const name_len = mem.sliceTo(default_dyld_path, 0).len;185 const name_len = mem.sliceTo(default_dyld_path, 0).len;
185 const cmdsize = @as(u32, @intCast(mem.alignForward(186 const cmdsize = @as(u32, @intCast(mem.alignForward(
186 u64,187 u64,
187 @sizeOf(macho.dylinker_command) + name_len,188 @sizeOf(macho.dylinker_command) + name_len,
188 @sizeOf(u64),189 @sizeOf(u64),
189 )));190 )));
190 try writer.writeStruct(macho.dylinker_command{191 try bw.writeStruct(macho.dylinker_command{
191 .cmd = .LOAD_DYLINKER,192 .cmd = .LOAD_DYLINKER,
192 .cmdsize = cmdsize,193 .cmdsize = cmdsize,
193 .name = @sizeOf(macho.dylinker_command),194 .name = @sizeOf(macho.dylinker_command),
194 });195 });
195 try writer.writeAll(mem.sliceTo(default_dyld_path, 0));196 try bw.writeAll(mem.sliceTo(default_dyld_path, 0));
196 const padding = cmdsize - @sizeOf(macho.dylinker_command) - name_len;197 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylinker_command) - name_len);
197 if (padding > 0) {
198 try writer.writeByteNTimes(0, padding);
199 }
200}198}
201199
202const WriteDylibLCCtx = struct {200const WriteDylibLCCtx = struct {
...@@ -207,14 +205,14 @@ const WriteDylibLCCtx = struct {...@@ -207,14 +205,14 @@ const WriteDylibLCCtx = struct {
207 compatibility_version: u32 = 0x10000,205 compatibility_version: u32 = 0x10000,
208};206};
209207
210pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {208pub fn writeDylibLC(ctx: WriteDylibLCCtx, bw: *Writer) !void {
211 const name_len = ctx.name.len + 1;209 const name_len = ctx.name.len + 1;
212 const cmdsize = @as(u32, @intCast(mem.alignForward(210 const cmdsize: u32 = @intCast(mem.alignForward(
213 u64,211 u64,
214 @sizeOf(macho.dylib_command) + name_len,212 @sizeOf(macho.dylib_command) + name_len,
215 @sizeOf(u64),213 @sizeOf(u64),
216 )));214 ));
217 try writer.writeStruct(macho.dylib_command{215 try bw.writeStruct(macho.dylib_command{
218 .cmd = ctx.cmd,216 .cmd = ctx.cmd,
219 .cmdsize = cmdsize,217 .cmdsize = cmdsize,
220 .dylib = .{218 .dylib = .{
...@@ -224,12 +222,9 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {...@@ -224,12 +222,9 @@ pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void {
224 .compatibility_version = ctx.compatibility_version,222 .compatibility_version = ctx.compatibility_version,
225 },223 },
226 });224 });
227 try writer.writeAll(ctx.name);225 try bw.writeAll(ctx.name);
228 try writer.writeByte(0);226 try bw.writeByte(0);
229 const padding = cmdsize - @sizeOf(macho.dylib_command) - name_len;227 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.dylib_command) - name_len);
230 if (padding > 0) {
231 try writer.writeByteNTimes(0, padding);
232 }
233}228}
234229
235pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {230pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
...@@ -258,26 +253,23 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {...@@ -258,26 +253,23 @@ pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void {
258 }, writer);253 }, writer);
259}254}
260255
261pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void {256pub fn writeRpathLC(bw: *Writer, rpath: []const u8) !void {
262 const rpath_len = rpath.len + 1;257 const rpath_len = rpath.len + 1;
263 const cmdsize = @as(u32, @intCast(mem.alignForward(258 const cmdsize = @as(u32, @intCast(mem.alignForward(
264 u64,259 u64,
265 @sizeOf(macho.rpath_command) + rpath_len,260 @sizeOf(macho.rpath_command) + rpath_len,
266 @sizeOf(u64),261 @sizeOf(u64),
267 )));262 )));
268 try writer.writeStruct(macho.rpath_command{263 try bw.writeStruct(macho.rpath_command{
269 .cmdsize = cmdsize,264 .cmdsize = cmdsize,
270 .path = @sizeOf(macho.rpath_command),265 .path = @sizeOf(macho.rpath_command),
271 });266 });
272 try writer.writeAll(rpath);267 try bw.writeAll(rpath);
273 try writer.writeByte(0);268 try bw.writeByte(0);
274 const padding = cmdsize - @sizeOf(macho.rpath_command) - rpath_len;269 try bw.splatByteAll(0, cmdsize - @sizeOf(macho.rpath_command) - rpath_len);
275 if (padding > 0) {
276 try writer.writeByteNTimes(0, padding);
277 }
278}270}
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 {
281 const cmd: macho.LC = switch (platform.os_tag) {273 const cmd: macho.LC = switch (platform.os_tag) {
282 .macos => .VERSION_MIN_MACOSX,274 .macos => .VERSION_MIN_MACOSX,
283 .ios => .VERSION_MIN_IPHONEOS,275 .ios => .VERSION_MIN_IPHONEOS,
...@@ -285,7 +277,7 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer...@@ -285,7 +277,7 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer
285 .watchos => .VERSION_MIN_WATCHOS,277 .watchos => .VERSION_MIN_WATCHOS,
286 else => unreachable,278 else => unreachable,
287 };279 };
288 try writer.writeAll(mem.asBytes(&macho.version_min_command{280 try bw.writeAll(mem.asBytes(&macho.version_min_command{
289 .cmd = cmd,281 .cmd = cmd,
290 .version = platform.toAppleVersion(),282 .version = platform.toAppleVersion(),
291 .sdk = if (sdk_version) |ver|283 .sdk = if (sdk_version) |ver|
...@@ -295,9 +287,9 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer...@@ -295,9 +287,9 @@ pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVer
295 }));287 }));
296}288}
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 {
299 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);291 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{
301 .cmdsize = cmdsize,293 .cmdsize = cmdsize,
302 .platform = platform.toApplePlatform(),294 .platform = platform.toApplePlatform(),
303 .minos = platform.toAppleVersion(),295 .minos = platform.toAppleVersion(),
...@@ -307,7 +299,7 @@ pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticV...@@ -307,7 +299,7 @@ pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticV
307 platform.toAppleVersion(),299 platform.toAppleVersion(),
308 .ntools = 1,300 .ntools = 1,
309 });301 });
310 try writer.writeAll(mem.asBytes(&macho.build_tool_version{302 try bw.writeAll(mem.asBytes(&macho.build_tool_version{
311 .tool = .ZIG,303 .tool = .ZIG,
312 .version = 0x0,304 .version = 0x0,
313 }));305 }));
src/link/MachO/relocatable.zig+31-58
...@@ -20,13 +20,13 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat...@@ -20,13 +20,13 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
20 // the *only* input file over.20 // the *only* input file over.
21 const path = positionals.items[0].path().?;21 const path = positionals.items[0].path().?;
22 const in_file = path.root_dir.handle.openFile(path.sub_path, .{}) catch |err|22 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) });
24 const stat = in_file.stat() catch |err|24 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) });
26 const amt = in_file.copyRangeAll(0, macho_file.base.file.?, 0, stat.size) catch |err|26 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) });
28 if (amt != stat.size)28 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});
30 return;30 return;
31 }31 }
3232
...@@ -62,7 +62,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat...@@ -62,7 +62,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
62 allocateSegment(macho_file);62 allocateSegment(macho_file);
6363
64 if (build_options.enable_logging) {64 if (build_options.enable_logging) {
65 state_log.debug("{}", .{macho_file.dumpState()});65 state_log.debug("{f}", .{macho_file.dumpState()});
66 }66 }
6767
68 try writeSections(macho_file);68 try writeSections(macho_file);
...@@ -126,7 +126,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -126,7 +126,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
126 allocateSegment(macho_file);126 allocateSegment(macho_file);
127127
128 if (build_options.enable_logging) {128 if (build_options.enable_logging) {
129 state_log.debug("{}", .{macho_file.dumpState()});129 state_log.debug("{f}", .{macho_file.dumpState()});
130 }130 }
131131
132 try writeSections(macho_file);132 try writeSections(macho_file);
...@@ -202,38 +202,30 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -202,38 +202,30 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
202 };202 };
203203
204 if (build_options.enable_logging) {204 if (build_options.enable_logging) {
205 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(macho_file)});205 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
206 }206 }
207207
208 var buffer = std.ArrayList(u8).init(gpa);208 var bw: Writer = .fixed(try gpa.alloc(u8, total_size));
209 defer buffer.deinit();209 defer gpa.free(bw.buffer);
210 try buffer.ensureTotalCapacityPrecise(total_size);
211 const writer = buffer.writer();
212210
213 // Write magic211 // Write magic
214 try writer.writeAll(Archive.ARMAG);212 bw.writeAll(Archive.ARMAG) catch unreachable;
215213
216 // Write symtab214 // Write symtab
217 ar_symtab.write(format, macho_file, writer) catch |err| switch (err) {215 ar_symtab.write(&bw, format, macho_file) catch |err| {
218 error.OutOfMemory => return error.OutOfMemory,216 return diags.fail("failed to write archive symbol table: {s}", .{@errorName(err)});
219 else => |e| return diags.fail("failed to write archive symbol table: {s}", .{@errorName(e)}),
220 };217 };
221218
222 // Write object files219 // Write object files
223 for (files.items) |index| {220 for (files.items) |index| {
224 const aligned = mem.alignForward(usize, buffer.items.len, 2);221 bw.splatByteAll(0, mem.alignForward(usize, bw.end, 2) - bw.end) catch unreachable;
225 const padding = aligned - buffer.items.len;222 macho_file.getFile(index).?.writeAr(&bw, format, macho_file) catch |err|
226 if (padding > 0) {
227 try writer.writeByteNTimes(0, padding);
228 }
229 macho_file.getFile(index).?.writeAr(format, macho_file, writer) catch |err|
230 return diags.fail("failed to write archive: {s}", .{@errorName(err)});223 return diags.fail("failed to write archive: {s}", .{@errorName(err)});
231 }224 }
232225
233 assert(buffer.items.len == total_size);226 assert(bw.end == bw.buffer.len);
234227 try macho_file.setEndPos(bw.end);
235 try macho_file.setEndPos(total_size);228 try macho_file.pwriteAll(bw.buffer, 0);
236 try macho_file.pwriteAll(buffer.items, 0);
237229
238 if (diags.hasErrors()) return error.LinkFailure;230 if (diags.hasErrors()) return error.LinkFailure;
239}231}
...@@ -672,7 +664,7 @@ fn writeCompactUnwindWorker(macho_file: *MachO, object: *Object) void {...@@ -672,7 +664,7 @@ fn writeCompactUnwindWorker(macho_file: *MachO, object: *Object) void {
672 diags.addError("failed to write '__LD,__eh_frame' section: {s}", .{@errorName(err)});664 diags.addError("failed to write '__LD,__eh_frame' section: {s}", .{@errorName(err)});
673}665}
674666
675fn writeSectionsToFile(macho_file: *MachO) !void {667fn writeSectionsToFile(macho_file: *MachO) link.File.FlushError!void {
676 const tracy = trace(@src());668 const tracy = trace(@src());
677 defer tracy.end();669 defer tracy.end();
678670
...@@ -689,12 +681,8 @@ fn writeSectionsToFile(macho_file: *MachO) !void {...@@ -689,12 +681,8 @@ fn writeSectionsToFile(macho_file: *MachO) !void {
689681
690fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } {682fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } {
691 const gpa = macho_file.base.comp.gpa;683 const gpa = macho_file.base.comp.gpa;
692 const needed_size = load_commands.calcLoadCommandsSizeObject(macho_file);684 var bw: Writer = .fixed(try gpa.alloc(u8, load_commands.calcLoadCommandsSizeObject(macho_file)));
693 const buffer = try gpa.alloc(u8, needed_size);685 defer gpa.free(bw.buffer);
694 defer gpa.free(buffer);
695
696 var stream = std.io.fixedBufferStream(buffer);
697 const writer = stream.writer();
698686
699 var ncmds: usize = 0;687 var ncmds: usize = 0;
700688
...@@ -702,47 +690,31 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc...@@ -702,47 +690,31 @@ fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struc
702 {690 {
703 assert(macho_file.segments.items.len == 1);691 assert(macho_file.segments.items.len == 1);
704 const seg = macho_file.segments.items[0];692 const seg = macho_file.segments.items[0];
705 writer.writeStruct(seg) catch |err| switch (err) {693 bw.writeStruct(seg) catch unreachable;
706 error.NoSpaceLeft => unreachable,
707 };
708 for (macho_file.sections.items(.header)) |header| {694 for (macho_file.sections.items(.header)) |header| {
709 writer.writeStruct(header) catch |err| switch (err) {695 bw.writeStruct(header) catch unreachable;
710 error.NoSpaceLeft => unreachable,
711 };
712 }696 }
713 ncmds += 1;697 ncmds += 1;
714 }698 }
715699
716 writer.writeStruct(macho_file.data_in_code_cmd) catch |err| switch (err) {700 bw.writeStruct(macho_file.data_in_code_cmd) catch unreachable;
717 error.NoSpaceLeft => unreachable,
718 };
719 ncmds += 1;701 ncmds += 1;
720 writer.writeStruct(macho_file.symtab_cmd) catch |err| switch (err) {702 bw.writeStruct(macho_file.symtab_cmd) catch unreachable;
721 error.NoSpaceLeft => unreachable,
722 };
723 ncmds += 1;703 ncmds += 1;
724 writer.writeStruct(macho_file.dysymtab_cmd) catch |err| switch (err) {704 bw.writeStruct(macho_file.dysymtab_cmd) catch unreachable;
725 error.NoSpaceLeft => unreachable,
726 };
727 ncmds += 1;705 ncmds += 1;
728706
729 if (macho_file.platform.isBuildVersionCompatible()) {707 if (macho_file.platform.isBuildVersionCompatible()) {
730 load_commands.writeBuildVersionLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {708 load_commands.writeBuildVersionLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable;
731 error.NoSpaceLeft => unreachable,
732 };
733 ncmds += 1;709 ncmds += 1;
734 } else {710 } else {
735 load_commands.writeVersionMinLC(macho_file.platform, macho_file.sdk_version, writer) catch |err| switch (err) {711 load_commands.writeVersionMinLC(&bw, macho_file.platform, macho_file.sdk_version) catch unreachable;
736 error.NoSpaceLeft => unreachable,
737 };
738 ncmds += 1;712 ncmds += 1;
739 }713 }
740714
741 assert(stream.pos == needed_size);715 assert(bw.end == bw.buffer.len);
742716 try macho_file.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64));
743 try macho_file.pwriteAll(buffer, @sizeOf(macho.mach_header_64));717 return .{ ncmds, bw.end };
744
745 return .{ ncmds, buffer.len };
746}718}
747719
748fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {720fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void {
...@@ -784,6 +756,7 @@ const macho = std.macho;...@@ -784,6 +756,7 @@ const macho = std.macho;
784const math = std.math;756const math = std.math;
785const mem = std.mem;757const mem = std.mem;
786const state_log = std.log.scoped(.link_state);758const state_log = std.log.scoped(.link_state);
759const Writer = std.io.Writer;
787760
788const Archive = @import("Archive.zig");761const Archive = @import("Archive.zig");
789const Atom = @import("Atom.zig");762const Atom = @import("Atom.zig");
src/link/MachO/synthetic.zig+124-151
...@@ -27,44 +27,37 @@ pub const GotSection = struct {...@@ -27,44 +27,37 @@ pub const GotSection = struct {
27 return got.symbols.items.len * @sizeOf(u64);27 return got.symbols.items.len * @sizeOf(u64);
28 }28 }
2929
30 pub fn write(got: GotSection, macho_file: *MachO, writer: anytype) !void {30 pub fn write(got: GotSection, macho_file: *MachO, bw: *Writer) !void {
31 const tracy = trace(@src());31 const tracy = trace(@src());
32 defer tracy.end();32 defer tracy.end();
33 for (got.symbols.items) |ref| {33 for (got.symbols.items) |ref| {
34 const sym = ref.getSymbol(macho_file).?;34 const sym = ref.getSymbol(macho_file).?;
35 const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file);35 const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file);
36 try writer.writeInt(u64, value, .little);36 try bw.writeInt(u64, value, .little);
37 }37 }
38 }38 }
3939
40 const FormatCtx = struct {40 const Format = struct {
41 got: GotSection,41 got: GotSection,
42 macho_file: *MachO,42 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 }
43 };56 };
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) {
46 return .{ .data = .{ .got = got, .macho_file = macho_file } };59 return .{ .data = .{ .got = got, .macho_file = macho_file } };
47 }60 }
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 }
68};61};
6962
70pub const StubsSection = struct {63pub const StubsSection = struct {
...@@ -96,7 +89,7 @@ pub const StubsSection = struct {...@@ -96,7 +89,7 @@ pub const StubsSection = struct {
96 return stubs.symbols.items.len * header.reserved2;89 return stubs.symbols.items.len * header.reserved2;
97 }90 }
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 {
100 const tracy = trace(@src());93 const tracy = trace(@src());
101 defer tracy.end();94 defer tracy.end();
102 const cpu_arch = macho_file.getTarget().cpu.arch;95 const cpu_arch = macho_file.getTarget().cpu.arch;
...@@ -108,54 +101,47 @@ pub const StubsSection = struct {...@@ -108,54 +101,47 @@ pub const StubsSection = struct {
108 const target = laptr_sect.addr + idx * @sizeOf(u64);101 const target = laptr_sect.addr + idx * @sizeOf(u64);
109 switch (cpu_arch) {102 switch (cpu_arch) {
110 .x86_64 => {103 .x86_64 => {
111 try writer.writeAll(&.{ 0xff, 0x25 });104 try bw.writeAll(&.{ 0xff, 0x25 });
112 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);105 try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little);
113 },106 },
114 .aarch64 => {107 .aarch64 => {
115 // TODO relax if possible108 // TODO relax if possible
116 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));109 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);
118 const off = try math.divExact(u12, @truncate(target), 8);111 const off = try math.divExact(u12, @truncate(target), 8);
119 try writer.writeInt(112 try bw.writeInt(
120 u32,113 u32,
121 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),114 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
122 .little,115 .little,
123 );116 );
124 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);117 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
125 },118 },
126 else => unreachable,119 else => unreachable,
127 }120 }
128 }121 }
129 }122 }
130123
131 const FormatCtx = struct {124 pub fn fmt(stubs: StubsSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
132 stubs: StubsSection,
133 macho_file: *MachO,
134 };
135
136 pub fn fmt(stubs: StubsSection, macho_file: *MachO) std.fmt.Formatter(format2) {
137 return .{ .data = .{ .stubs = stubs, .macho_file = macho_file } };125 return .{ .data = .{ .stubs = stubs, .macho_file = macho_file } };
138 }126 }
139127
140 pub fn format2(128 const Format = struct {
141 ctx: FormatCtx,129 stubs: StubsSection,
142 comptime unused_fmt_string: []const u8,130 macho_file: *MachO,
143 options: std.fmt.FormatOptions,131
144 writer: anytype,132 pub fn print(f: Format, w: *Writer) Writer.Error!void {
145 ) !void {133 for (f.stubs.symbols.items, 0..) |ref, i| {
146 _ = options;134 const symbol = ref.getSymbol(f.macho_file).?;
147 _ = unused_fmt_string;135 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
148 for (ctx.stubs.symbols.items, 0..) |ref, i| {136 i,
149 const symbol = ref.getSymbol(ctx.macho_file).?;137 symbol.getStubsAddress(f.macho_file),
150 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{138 ref,
151 i,139 symbol.getAddress(.{}, f.macho_file),
152 symbol.getStubsAddress(ctx.macho_file),140 symbol.getName(f.macho_file),
153 ref,141 });
154 symbol.getAddress(.{}, ctx.macho_file),142 }
155 symbol.getName(ctx.macho_file),
156 });
157 }143 }
158 }144 };
159};145};
160146
161pub const StubsHelperSection = struct {147pub const StubsHelperSection = struct {
...@@ -189,11 +175,11 @@ pub const StubsHelperSection = struct {...@@ -189,11 +175,11 @@ pub const StubsHelperSection = struct {
189 return s;175 return s;
190 }176 }
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 {
193 const tracy = trace(@src());179 const tracy = trace(@src());
194 defer tracy.end();180 defer tracy.end();
195181
196 try stubs_helper.writePreamble(macho_file, writer);182 try stubs_helper.writePreamble(macho_file, bw);
197183
198 const cpu_arch = macho_file.getTarget().cpu.arch;184 const cpu_arch = macho_file.getTarget().cpu.arch;
199 const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];185 const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
...@@ -209,24 +195,24 @@ pub const StubsHelperSection = struct {...@@ -209,24 +195,24 @@ pub const StubsHelperSection = struct {
209 const target: i64 = @intCast(sect.addr);195 const target: i64 = @intCast(sect.addr);
210 switch (cpu_arch) {196 switch (cpu_arch) {
211 .x86_64 => {197 .x86_64 => {
212 try writer.writeByte(0x68);198 try bw.writeByte(0x68);
213 try writer.writeInt(u32, offset, .little);199 try bw.writeInt(u32, offset, .little);
214 try writer.writeByte(0xe9);200 try bw.writeByte(0xe9);
215 try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);201 try bw.writeInt(i32, @intCast(target - source - 6 - 4), .little);
216 },202 },
217 .aarch64 => {203 .aarch64 => {
218 const literal = blk: {204 const literal = blk: {
219 const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);205 const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);
220 break :blk std.math.cast(u18, div_res) orelse return error.Overflow;206 break :blk std.math.cast(u18, div_res) orelse return error.Overflow;
221 };207 };
222 try writer.writeInt(u32, aarch64.Instruction.ldrLiteral(208 try bw.writeInt(u32, aarch64.Instruction.ldrLiteral(
223 .w16,209 .w16,
224 literal,210 literal,
225 ).toU32(), .little);211 ).toU32(), .little);
226 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse212 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse
227 return error.Overflow;213 return error.Overflow;
228 try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);214 try bw.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
229 try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });215 try bw.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
230 },216 },
231 else => unreachable,217 else => unreachable,
232 }218 }
...@@ -234,7 +220,7 @@ pub const StubsHelperSection = struct {...@@ -234,7 +220,7 @@ pub const StubsHelperSection = struct {
234 }220 }
235 }221 }
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 {
238 _ = stubs_helper;224 _ = stubs_helper;
239 const obj = macho_file.getInternalObject().?;225 const obj = macho_file.getInternalObject().?;
240 const cpu_arch = macho_file.getTarget().cpu.arch;226 const cpu_arch = macho_file.getTarget().cpu.arch;
...@@ -249,21 +235,21 @@ pub const StubsHelperSection = struct {...@@ -249,21 +235,21 @@ pub const StubsHelperSection = struct {
249 };235 };
250 switch (cpu_arch) {236 switch (cpu_arch) {
251 .x86_64 => {237 .x86_64 => {
252 try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d });238 try bw.writeAll(&.{ 0x4c, 0x8d, 0x1d });
253 try writer.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);239 try bw.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);
254 try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });240 try bw.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
255 try writer.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);241 try bw.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);
256 try writer.writeByte(0x90);242 try bw.writeByte(0x90);
257 },243 },
258 .aarch64 => {244 .aarch64 => {
259 {245 {
260 // TODO relax if possible246 // TODO relax if possible
261 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));247 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));
262 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);248 try bw.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
263 const off: u12 = @truncate(dyld_private_addr);249 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);
265 }251 }
266 try writer.writeInt(u32, aarch64.Instruction.stp(252 try bw.writeInt(u32, aarch64.Instruction.stp(
267 .x16,253 .x16,
268 .x17,254 .x17,
269 aarch64.Register.sp,255 aarch64.Register.sp,
...@@ -272,15 +258,15 @@ pub const StubsHelperSection = struct {...@@ -272,15 +258,15 @@ pub const StubsHelperSection = struct {
272 {258 {
273 // TODO relax if possible259 // TODO relax if possible
274 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));260 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));
275 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);261 try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
276 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);262 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);
277 try writer.writeInt(u32, aarch64.Instruction.ldr(263 try bw.writeInt(u32, aarch64.Instruction.ldr(
278 .x16,264 .x16,
279 .x16,265 .x16,
280 aarch64.Instruction.LoadStoreOffset.imm(off),266 aarch64.Instruction.LoadStoreOffset.imm(off),
281 ).toU32(), .little);267 ).toU32(), .little);
282 }268 }
283 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);269 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
284 },270 },
285 else => unreachable,271 else => unreachable,
286 }272 }
...@@ -293,7 +279,7 @@ pub const LaSymbolPtrSection = struct {...@@ -293,7 +279,7 @@ pub const LaSymbolPtrSection = struct {
293 return macho_file.stubs.symbols.items.len * @sizeOf(u64);279 return macho_file.stubs.symbols.items.len * @sizeOf(u64);
294 }280 }
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 {
297 const tracy = trace(@src());283 const tracy = trace(@src());
298 defer tracy.end();284 defer tracy.end();
299 _ = laptr;285 _ = laptr;
...@@ -304,12 +290,12 @@ pub const LaSymbolPtrSection = struct {...@@ -304,12 +290,12 @@ pub const LaSymbolPtrSection = struct {
304 const sym = ref.getSymbol(macho_file).?;290 const sym = ref.getSymbol(macho_file).?;
305 if (sym.flags.weak) {291 if (sym.flags.weak) {
306 const value = sym.getAddress(.{ .stubs = false }, macho_file);292 const value = sym.getAddress(.{ .stubs = false }, macho_file);
307 try writer.writeInt(u64, @intCast(value), .little);293 try bw.writeInt(u64, @intCast(value), .little);
308 } else {294 } else {
309 const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) +295 const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) +
310 StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx;296 StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx;
311 stub_helper_idx += 1;297 stub_helper_idx += 1;
312 try writer.writeInt(u64, @intCast(value), .little);298 try bw.writeInt(u64, @intCast(value), .little);
313 }299 }
314 }300 }
315 }301 }
...@@ -343,48 +329,41 @@ pub const TlvPtrSection = struct {...@@ -343,48 +329,41 @@ pub const TlvPtrSection = struct {
343 return tlv.symbols.items.len * @sizeOf(u64);329 return tlv.symbols.items.len * @sizeOf(u64);
344 }330 }
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 {
347 const tracy = trace(@src());333 const tracy = trace(@src());
348 defer tracy.end();334 defer tracy.end();
349335
350 for (tlv.symbols.items) |ref| {336 for (tlv.symbols.items) |ref| {
351 const sym = ref.getSymbol(macho_file).?;337 const sym = ref.getSymbol(macho_file).?;
352 if (sym.flags.import) {338 if (sym.flags.import) {
353 try writer.writeInt(u64, 0, .little);339 try bw.writeInt(u64, 0, .little);
354 } else {340 } else {
355 try writer.writeInt(u64, sym.getAddress(.{}, macho_file), .little);341 try bw.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
356 }342 }
357 }343 }
358 }344 }
359345
360 const FormatCtx = struct {346 pub fn fmt(tlv: TlvPtrSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
361 tlv: TlvPtrSection,
362 macho_file: *MachO,
363 };
364
365 pub fn fmt(tlv: TlvPtrSection, macho_file: *MachO) std.fmt.Formatter(format2) {
366 return .{ .data = .{ .tlv = tlv, .macho_file = macho_file } };347 return .{ .data = .{ .tlv = tlv, .macho_file = macho_file } };
367 }348 }
368349
369 pub fn format2(350 const Format = struct {
370 ctx: FormatCtx,351 tlv: TlvPtrSection,
371 comptime unused_fmt_string: []const u8,352 macho_file: *MachO,
372 options: std.fmt.FormatOptions,353
373 writer: anytype,354 pub fn print(f: Format, w: *Writer) Writer.Error!void {
374 ) !void {355 for (f.tlv.symbols.items, 0..) |ref, i| {
375 _ = options;356 const symbol = ref.getSymbol(f.macho_file).?;
376 _ = unused_fmt_string;357 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
377 for (ctx.tlv.symbols.items, 0..) |ref, i| {358 i,
378 const symbol = ref.getSymbol(ctx.macho_file).?;359 symbol.getTlvPtrAddress(f.macho_file),
379 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{360 ref,
380 i,361 symbol.getAddress(.{}, f.macho_file),
381 symbol.getTlvPtrAddress(ctx.macho_file),362 symbol.getName(f.macho_file),
382 ref,363 });
383 symbol.getAddress(.{}, ctx.macho_file),364 }
384 symbol.getName(ctx.macho_file),
385 });
386 }365 }
387 }366 };
388};367};
389368
390pub const ObjcStubsSection = struct {369pub const ObjcStubsSection = struct {
...@@ -421,7 +400,7 @@ pub const ObjcStubsSection = struct {...@@ -421,7 +400,7 @@ pub const ObjcStubsSection = struct {
421 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);400 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
422 }401 }
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 {
425 const tracy = trace(@src());404 const tracy = trace(@src());
426 defer tracy.end();405 defer tracy.end();
427406
...@@ -432,18 +411,18 @@ pub const ObjcStubsSection = struct {...@@ -432,18 +411,18 @@ pub const ObjcStubsSection = struct {
432 const addr = objc.getAddress(@intCast(idx), macho_file);411 const addr = objc.getAddress(@intCast(idx), macho_file);
433 switch (macho_file.getTarget().cpu.arch) {412 switch (macho_file.getTarget().cpu.arch) {
434 .x86_64 => {413 .x86_64 => {
435 try writer.writeAll(&.{ 0x48, 0x8b, 0x35 });414 try bw.writeAll(&.{ 0x48, 0x8b, 0x35 });
436 {415 {
437 const target = sym.getObjcSelrefsAddress(macho_file);416 const target = sym.getObjcSelrefsAddress(macho_file);
438 const source = addr;417 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);
440 }419 }
441 try writer.writeAll(&.{ 0xff, 0x25 });420 try bw.writeAll(&.{ 0xff, 0x25 });
442 {421 {
443 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;422 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
444 const target = target_sym.getGotAddress(macho_file);423 const target = target_sym.getGotAddress(macho_file);
445 const source = addr + 7;424 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);
447 }426 }
448 },427 },
449 .aarch64 => {428 .aarch64 => {
...@@ -451,9 +430,9 @@ pub const ObjcStubsSection = struct {...@@ -451,9 +430,9 @@ pub const ObjcStubsSection = struct {
451 const target = sym.getObjcSelrefsAddress(macho_file);430 const target = sym.getObjcSelrefsAddress(macho_file);
452 const source = addr;431 const source = addr;
453 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));432 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);
455 const off = try math.divExact(u12, @truncate(target), 8);434 const off = try math.divExact(u12, @truncate(target), 8);
456 try writer.writeInt(435 try bw.writeInt(
457 u32,436 u32,
458 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),437 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
459 .little,438 .little,
...@@ -464,52 +443,45 @@ pub const ObjcStubsSection = struct {...@@ -464,52 +443,45 @@ pub const ObjcStubsSection = struct {
464 const target = target_sym.getGotAddress(macho_file);443 const target = target_sym.getGotAddress(macho_file);
465 const source = addr + 2 * @sizeOf(u32);444 const source = addr + 2 * @sizeOf(u32);
466 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));445 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);
468 const off = try math.divExact(u12, @truncate(target), 8);447 const off = try math.divExact(u12, @truncate(target), 8);
469 try writer.writeInt(448 try bw.writeInt(
470 u32,449 u32,
471 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),450 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
472 .little,451 .little,
473 );452 );
474 }453 }
475 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);454 try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
476 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);455 try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
477 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);456 try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
478 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);457 try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
479 },458 },
480 else => unreachable,459 else => unreachable,
481 }460 }
482 }461 }
483 }462 }
484463
485 const FormatCtx = struct {464 pub fn fmt(objc: ObjcStubsSection, macho_file: *MachO) std.fmt.Formatter(Format, Format.print) {
486 objc: ObjcStubsSection,
487 macho_file: *MachO,
488 };
489
490 pub fn fmt(objc: ObjcStubsSection, macho_file: *MachO) std.fmt.Formatter(format2) {
491 return .{ .data = .{ .objc = objc, .macho_file = macho_file } };465 return .{ .data = .{ .objc = objc, .macho_file = macho_file } };
492 }466 }
493467
494 pub fn format2(468 const Format = struct {
495 ctx: FormatCtx,469 objc: ObjcStubsSection,
496 comptime unused_fmt_string: []const u8,470 macho_file: *MachO,
497 options: std.fmt.FormatOptions,471
498 writer: anytype,472 pub fn print(f: Format, w: *Writer) Writer.Error!void {
499 ) !void {473 for (f.objc.symbols.items, 0..) |ref, i| {
500 _ = options;474 const symbol = ref.getSymbol(f.macho_file).?;
501 _ = unused_fmt_string;475 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
502 for (ctx.objc.symbols.items, 0..) |ref, i| {476 i,
503 const symbol = ref.getSymbol(ctx.macho_file).?;477 symbol.getObjcStubsAddress(f.macho_file),
504 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{478 ref,
505 i,479 symbol.getAddress(.{}, f.macho_file),
506 symbol.getObjcStubsAddress(ctx.macho_file),480 symbol.getName(f.macho_file),
507 ref,481 });
508 symbol.getAddress(.{}, ctx.macho_file),482 }
509 symbol.getName(ctx.macho_file),
510 });
511 }483 }
512 }484 };
513485
514 pub const Index = u32;486 pub const Index = u32;
515};487};
...@@ -524,7 +496,7 @@ pub const Indsymtab = struct {...@@ -524,7 +496,7 @@ pub const Indsymtab = struct {
524 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);496 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
525 }497 }
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 {
528 const tracy = trace(@src());500 const tracy = trace(@src());
529 defer tracy.end();501 defer tracy.end();
530502
...@@ -533,21 +505,21 @@ pub const Indsymtab = struct {...@@ -533,21 +505,21 @@ pub const Indsymtab = struct {
533 for (macho_file.stubs.symbols.items) |ref| {505 for (macho_file.stubs.symbols.items) |ref| {
534 const sym = ref.getSymbol(macho_file).?;506 const sym = ref.getSymbol(macho_file).?;
535 if (sym.getOutputSymtabIndex(macho_file)) |idx| {507 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
536 try writer.writeInt(u32, idx, .little);508 try bw.writeInt(u32, idx, .little);
537 }509 }
538 }510 }
539511
540 for (macho_file.got.symbols.items) |ref| {512 for (macho_file.got.symbols.items) |ref| {
541 const sym = ref.getSymbol(macho_file).?;513 const sym = ref.getSymbol(macho_file).?;
542 if (sym.getOutputSymtabIndex(macho_file)) |idx| {514 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
543 try writer.writeInt(u32, idx, .little);515 try bw.writeInt(u32, idx, .little);
544 }516 }
545 }517 }
546518
547 for (macho_file.stubs.symbols.items) |ref| {519 for (macho_file.stubs.symbols.items) |ref| {
548 const sym = ref.getSymbol(macho_file).?;520 const sym = ref.getSymbol(macho_file).?;
549 if (sym.getOutputSymtabIndex(macho_file)) |idx| {521 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
550 try writer.writeInt(u32, idx, .little);522 try bw.writeInt(u32, idx, .little);
551 }523 }
552 }524 }
553 }525 }
...@@ -601,7 +573,7 @@ pub const DataInCode = struct {...@@ -601,7 +573,7 @@ pub const DataInCode = struct {
601 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;573 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;
602 }574 }
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 {
605 const base_address = if (!macho_file.base.isRelocatable())577 const base_address = if (!macho_file.base.isRelocatable())
606 macho_file.getTextSegment().vmaddr578 macho_file.getTextSegment().vmaddr
607 else579 else
...@@ -609,7 +581,7 @@ pub const DataInCode = struct {...@@ -609,7 +581,7 @@ pub const DataInCode = struct {
609 for (dice.entries.items) |entry| {581 for (dice.entries.items) |entry| {
610 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);582 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);
611 const offset = atom_address + entry.offset - base_address;583 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{
613 .offset = @intCast(offset),585 .offset = @intCast(offset),
614 .length = entry.length,586 .length = entry.length,
615 .kind = entry.kind,587 .kind = entry.kind,
...@@ -625,13 +597,14 @@ pub const DataInCode = struct {...@@ -625,13 +597,14 @@ pub const DataInCode = struct {
625 };597 };
626};598};
627599
600const std = @import("std");
628const aarch64 = @import("../aarch64.zig");601const aarch64 = @import("../aarch64.zig");
629const assert = std.debug.assert;602const assert = std.debug.assert;
630const macho = std.macho;603const macho = std.macho;
631const math = std.math;604const math = std.math;
632const std = @import("std");
633const trace = @import("../../tracy.zig").trace;
634
635const Allocator = std.mem.Allocator;605const Allocator = std.mem.Allocator;
606const Writer = std.io.Writer;
607
608const trace = @import("../../tracy.zig").trace;
636const MachO = @import("../MachO.zig");609const MachO = @import("../MachO.zig");
637const Symbol = @import("Symbol.zig");610const Symbol = @import("Symbol.zig");