| author | |
| committer | |
| log | c8fcd2ff2c032b2de8cc1a57e075552d1cab35df |
| tree | 7155f58049ecd0e948533f6b64cba1553dd33ae2 |
| parent | f71d97e4cbb0e56213cb76657ad6c9edf6134868 |
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 | } |
| 526 | 526 | ||
| 527 | const MsgWriter = struct { | 527 | const 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, |
| 530 | 530 | ||
| 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 | |||
| 3 | const std = @import("std"); | ||
| 4 | const math = std.math; | ||
| 5 | const mem = std.mem; | ||
| 6 | const Allocator = mem.Allocator; | ||
| 7 | const assert = std.debug.assert; | ||
| 8 | const testing = std.testing; | ||
| 9 | |||
| 10 | pub 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 | |||
| 304 | test "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 | |||
| 312 | test "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 | |||
| 400 | test 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 }, |
| 41 | uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 }, | 41 | uuid_cmd: macho.uuid_command = .{ .uuid = [_]u8{0} ** 16 }, |
| 42 | codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE }, | 42 | codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE }, |
| 43 | 43 | ||
| 44 | pagezero_seg_index: ?u8 = null, | 44 | pagezero_seg_index: ?u4 = null, |
| 45 | text_seg_index: ?u8 = null, | 45 | text_seg_index: ?u4 = null, |
| 46 | linkedit_seg_index: ?u8 = null, | 46 | linkedit_seg_index: ?u4 = null, |
| 47 | text_sect_index: ?u8 = null, | 47 | text_sect_index: ?u8 = null, |
| 48 | data_sect_index: ?u8 = null, | 48 | data_sect_index: ?u8 = null, |
| 49 | got_sect_index: ?u8 = null, | 49 | got_sect_index: ?u8 = null, |
| ... | @@ -76,10 +76,10 @@ unwind_info: UnwindInfo = .{}, | ... | @@ -76,10 +76,10 @@ unwind_info: UnwindInfo = .{}, |
| 76 | data_in_code: DataInCode = .{}, | 76 | data_in_code: DataInCode = .{}, |
| 77 | 77 | ||
| 78 | /// Tracked loadable segments during incremental linking. | 78 | /// Tracked loadable segments during incremental linking. |
| 79 | zig_text_seg_index: ?u8 = null, | 79 | zig_text_seg_index: ?u4 = null, |
| 80 | zig_const_seg_index: ?u8 = null, | 80 | zig_const_seg_index: ?u4 = null, |
| 81 | zig_data_seg_index: ?u8 = null, | 81 | zig_data_seg_index: ?u4 = null, |
| 82 | zig_bss_seg_index: ?u8 = null, | 82 | zig_bss_seg_index: ?u4 = null, |
| 83 | 83 | ||
| 84 | /// Tracked section headers with incremental updates to Zig object. | 84 | /// Tracked section headers with incremental updates to Zig object. |
| 85 | zig_text_sect_index: ?u8 = null, | 85 | zig_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(); |
| 544 | 544 | ||
| 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 | } |
| 548 | 548 | ||
| 549 | // Beyond this point, everything has been allocated a virtual address and we can resolve | 549 | // 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 { |
| 677 | 678 | ||
| 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})); |
| 681 | 682 | ||
| 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 | } |
| 687 | 688 | ||
| 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 { |
| 863 | 864 | ||
| 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 classified | 866 | // 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}); |
| 867 | 868 | ||
| 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( |
| 1074 | 1075 | ||
| 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( |
| 1097 | 1098 | ||
| 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 | } |
| 1596 | 1597 | ||
| 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 { |
| 2131 | 2132 | ||
| 2132 | mem.sort(Entry, entries.items, self, Entry.lessThan); | 2133 | mem.sort(Entry, entries.items, self, Entry.lessThan); |
| 2133 | 2134 | ||
| 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 | } |
| 2147 | 2148 | ||
| 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 { |
| 2526 | 2527 | ||
| 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 { |
| 2556 | 2555 | ||
| 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; |
| 2667 | 2666 | ||
| 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(); | ||
| 2674 | 2670 | ||
| 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 | } |
| 2686 | 2682 | ||
| 2687 | pub fn writeDataInCode(self: *MachO) !void { | 2683 | pub 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 | } |
| 2697 | 2696 | ||
| 2698 | fn writeIndsymtab(self: *MachO) !void { | 2697 | fn 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 | } |
| 2709 | 2711 | ||
| 2710 | pub fn writeSymtabToFile(self: *MachO) !void { | 2712 | pub 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 | } |
| 2816 | 2818 | ||
| 2817 | fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { | 2819 | fn 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); | ||
| 2823 | 2822 | ||
| 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); |
| 2826 | 2825 | ||
| 2827 | var ncmds: usize = 0; | 2826 | var ncmds: usize = 0; |
| 2828 | 2827 | ||
| ... | @@ -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 | } |
| 2842 | 2841 | ||
| 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; |
| 2855 | 2854 | ||
| 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 | 0 | 2860 | 0 |
| 2862 | else | 2861 | 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 | } |
| 2871 | 2870 | ||
| 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 | } |
| 2876 | 2875 | ||
| 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 | } |
| 2888 | 2887 | ||
| 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; |
| 2891 | 2890 | ||
| 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 | } |
| 2899 | 2898 | ||
| 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; |
| 2903 | 2902 | ||
| 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 | } |
| 2922 | 2921 | ||
| 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 | } |
| 2927 | 2926 | ||
| 2928 | assert(stream.pos == needed_size); | 2927 | assert(bw.end == bw.buffer.len); |
| 2929 | 2928 | try self.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64)); | |
| 2930 | try self.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); | ||
| 2931 | 2929 | ||
| 2932 | return .{ ncmds, buffer.len, uuid_cmd_offset }; | 2930 | return .{ ncmds, bw.end, uuid_cmd_offset }; |
| 2933 | } | 2931 | } |
| 2934 | 2932 | ||
| 2935 | fn writeHeader(self: *MachO, ncmds: usize, sizeofcmds: usize) !void { | 2933 | fn 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 | } |
| 3013 | 3011 | ||
| 3014 | pub fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void { | 3012 | pub 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; |
| 3017 | 3016 | ||
| 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()); | ||
| 3029 | 3026 | ||
| 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 | }); |
| 3034 | 3031 | ||
| 3035 | try self.pwriteAll(buffer.items, offset); | 3032 | assert(bw.end == bw.buffer.len); |
| 3033 | try self.pwriteAll(bw.buffer, offset); | ||
| 3036 | } | 3034 | } |
| 3037 | 3035 | ||
| 3038 | pub fn updateFunc( | 3036 | pub 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 | } |
| 3342 | 3340 | ||
| 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 | } |
| 3601 | 3599 | ||
| 3602 | pub fn isZigSegment(self: MachO, seg_id: u8) bool { | 3600 | pub 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 | } |
| 3702 | 3700 | ||
| 3703 | pub fn getSegmentByName(self: MachO, segname: []const u8) ?u8 { | 3701 | pub 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 | } |
| 3708 | 3706 | ||
| ... | @@ -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 | } |
| 3796 | 3794 | ||
| 3797 | fn reportMissingDependencyError( | 3795 | fn 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 | } |
| 3828 | 3826 | ||
| 3829 | fn reportDuplicates(self: *MachO) error{ HasDuplicates, OutOfMemory }!void { | 3827 | fn 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 { |
| 3853 | 3851 | ||
| 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()}); |
| 3857 | 3855 | ||
| 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 | } |
| 3863 | 3861 | ||
| 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 | } |
| 3902 | 3900 | ||
| 3903 | pub fn dumpState(self: *MachO) std.fmt.Formatter(fmtDumpState) { | 3901 | pub fn dumpState(self: *MachO) std.fmt.Formatter(*MachO, fmtDumpState) { |
| 3904 | return .{ .data = self }; | 3902 | return .{ .data = self }; |
| 3905 | } | 3903 | } |
| 3906 | 3904 | ||
| 3907 | fn fmtDumpState( | 3905 | fn 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 | } |
| 3967 | 3958 | ||
| 3968 | fn fmtSections(self: *MachO) std.fmt.Formatter(formatSections) { | 3959 | fn fmtSections(self: *MachO) std.fmt.Formatter(*MachO, formatSections) { |
| 3969 | return .{ .data = self }; | 3960 | return .{ .data = self }; |
| 3970 | } | 3961 | } |
| 3971 | 3962 | ||
| 3972 | fn formatSections( | 3963 | fn 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 | } |
| 3991 | 3975 | ||
| 3992 | fn fmtSegments(self: *MachO) std.fmt.Formatter(formatSegments) { | 3976 | fn fmtSegments(self: *MachO) std.fmt.Formatter(*MachO, formatSegments) { |
| 3993 | return .{ .data = self }; | 3977 | return .{ .data = self }; |
| 3994 | } | 3978 | } |
| 3995 | 3979 | ||
| 3996 | fn formatSegments( | 3980 | fn 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 | } |
| 4011 | 3988 | ||
| 4012 | pub fn fmtSectType(tt: u8) std.fmt.Formatter(formatSectType) { | 3989 | pub fn fmtSectType(tt: u8) std.fmt.Formatter(u8, formatSectType) { |
| 4013 | return .{ .data = tt }; | 3990 | return .{ .data = tt }; |
| 4014 | } | 3991 | } |
| 4015 | 3992 | ||
| 4016 | fn formatSectType( | 3993 | fn 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 | } |
| 4051 | 4021 | ||
| 4052 | const is_hot_update_compatible = switch (builtin.target.os.tag) { | 4022 | const 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"; |
| 4058 | 4028 | ||
| 4059 | const Section = struct { | 4029 | const 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 | } |
| 4281 | 4251 | ||
| 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 | } |
| 4285 | 4255 | ||
| 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 | }; | ||
| 4290 | 4259 | ||
| 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 | }; |
| 4304 | 4267 | ||
| 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. |
| 4391 | fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 { | 4354 | fn 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 | }; |
| 4407 | 4370 | ||
| 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 | } |
| 4509 | 4472 | ||
| 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 | }; |
| 4521 | 4478 | ||
| ... | @@ -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"); |
| 5317 | 5274 | ||
| 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 | } |
| 5321 | 5278 | ||
| ... | @@ -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 { |
| 5360 | pub fn pwriteAll(macho_file: *MachO, bytes: []const u8, offset: u64) error{LinkFailure}!void { | 5317 | pub 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 | } |
| 5367 | 5327 | ||
| ... | @@ -5414,6 +5374,7 @@ const macho = std.macho; | ... | @@ -5414,6 +5374,7 @@ const macho = std.macho; |
| 5414 | const math = std.math; | 5374 | const math = std.math; |
| 5415 | const mem = std.mem; | 5375 | const mem = std.mem; |
| 5416 | const meta = std.meta; | 5376 | const meta = std.meta; |
| 5377 | const Writer = std.io.Writer; | ||
| 5417 | 5378 | ||
| 5418 | const aarch64 = @import("../arch/aarch64/bits.zig"); | 5379 | const aarch64 = @import("../arch/aarch64/bits.zig"); |
| 5419 | const bind = @import("MachO/dyld_info/bind.zig"); | 5380 | const 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 | }; |
| 73 | 73 | ||
| 74 | log.debug("extracting object '{}' from archive '{}'", .{ object.path, path }); | 74 | log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path }); |
| 75 | 75 | ||
| 76 | try self.objects.append(gpa, object); | 76 | try self.objects.append(gpa, object); |
| 77 | } | 77 | } |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | pub fn writeHeader( | 80 | pub 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; |
| 104 | 93 | _ = 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 | } |
| 122 | 98 | ||
| 123 | // Archive files start with the ARMAG identifying string. Then follows a | 99 | // 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 | } |
| 203 | 179 | ||
| 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 | // Header | 182 | // Header |
| 207 | try writeHeader(SYMDEF, ar.size(format), format, writer); | 183 | try writeHeader(bw, SYMDEF, ar.size(format), format); |
| 208 | // Symtab size | 184 | // 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 entries | 186 | // 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 offset | 193 | // Name offset |
| 218 | try writeInt(format, entry.off, writer); | 194 | try writeInt(bw, format, entry.off); |
| 219 | // File offset | 195 | // File offset |
| 220 | try writeInt(format, file_off, writer); | 196 | try writeInt(bw, format, file_off); |
| 221 | } | 197 | } |
| 222 | // Strtab size | 198 | // 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 | // Strtab | 201 | // 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 | } |
| 232 | 205 | ||
| 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 | }; |
| 237 | 220 | ||
| 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 | } |
| 241 | 224 | ||
| 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 offset | 226 | /// 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 | } |
| 284 | 250 | ||
| 285 | pub fn writeInt(format: Format, value: u64, writer: anytype) !void { | 251 | pub 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 | } |
| 291 | 257 | ||
| ... | @@ -304,8 +270,9 @@ const log = std.log.scoped(.link); | ... | @@ -304,8 +270,9 @@ const log = std.log.scoped(.link); |
| 304 | const macho = std.macho; | 270 | const macho = std.macho; |
| 305 | const mem = std.mem; | 271 | const mem = std.mem; |
| 306 | const std = @import("std"); | 272 | const std = @import("std"); |
| 307 | const Allocator = mem.Allocator; | 273 | const Allocator = std.mem.Allocator; |
| 308 | const Path = std.Build.Cache.Path; | 274 | const Path = std.Build.Cache.Path; |
| 275 | const Writer = std.io.Writer; | ||
| 309 | 276 | ||
| 310 | const Archive = @This(); | 277 | const Archive = @This(); |
| 311 | const File = @import("file.zig").File; | 278 | const 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 { |
| 580 | 580 | ||
| 581 | relocs_log.debug("{x}: {s}", .{ self.value, name }); | 581 | relocs_log.debug("{x}: {s}", .{ self.value, name }); |
| 582 | 582 | ||
| 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 | } |
| 594 | 595 | ||
| 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 | } |
| 621 | 620 | ||
| ... | @@ -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; |
| 665 | 664 | ||
| 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 | }, |
| 703 | 702 | ||
| ... | @@ -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 | }, |
| 710 | 709 | ||
| 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"); |
| 715 | 714 | ||
| 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 | }, |
| 741 | 740 | ||
| ... | @@ -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 | }, |
| 755 | 754 | ||
| 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 | }, |
| 761 | 760 | ||
| 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 | }, |
| 814 | 813 | ||
| ... | @@ -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 | } |
| 939 | 938 | ||
| 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 | } |
| 947 | 943 | ||
| 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 | } |
| 1004 | 1000 | ||
| 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 | } |
| 1119 | 1115 | ||
| 1120 | pub fn format( | 1116 | pub 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 | |||
| 1133 | pub 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 | } |
| 1139 | 1122 | ||
| 1140 | const FormatContext = struct { | 1123 | const Format = struct { |
| 1141 | atom: Atom, | 1124 | atom: Atom, |
| 1142 | macho_file: *MachO, | 1125 | macho_file: *MachO, |
| 1143 | }; | ||
| 1144 | 1126 | ||
| 1145 | fn 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 | }; |
| 1174 | 1150 | ||
| 1175 | pub const Index = u32; | 1151 | pub const Index = u32; |
| 1176 | 1152 | ||
| ... | @@ -1205,19 +1181,20 @@ pub const Extra = struct { | ... | @@ -1205,19 +1181,20 @@ pub const Extra = struct { |
| 1205 | 1181 | ||
| 1206 | pub const Alignment = @import("../../InternPool.zig").Alignment; | 1182 | pub const Alignment = @import("../../InternPool.zig").Alignment; |
| 1207 | 1183 | ||
| 1208 | const aarch64 = @import("../aarch64.zig"); | 1184 | const std = @import("std"); |
| 1209 | const assert = std.debug.assert; | 1185 | const assert = std.debug.assert; |
| 1210 | const macho = std.macho; | 1186 | const macho = std.macho; |
| 1211 | const math = std.math; | 1187 | const math = std.math; |
| 1212 | const mem = std.mem; | 1188 | const mem = std.mem; |
| 1213 | const log = std.log.scoped(.link); | 1189 | const log = std.log.scoped(.link); |
| 1214 | const relocs_log = std.log.scoped(.link_relocs); | 1190 | const relocs_log = std.log.scoped(.link_relocs); |
| 1215 | const std = @import("std"); | 1191 | const Writer = std.io.Writer; |
| 1216 | const trace = @import("../../tracy.zig").trace; | ||
| 1217 | |||
| 1218 | const Allocator = mem.Allocator; | 1192 | const Allocator = mem.Allocator; |
| 1219 | const Atom = @This(); | ||
| 1220 | const AtomicBool = std.atomic.Value(bool); | 1193 | const AtomicBool = std.atomic.Value(bool); |
| 1194 | |||
| 1195 | const aarch64 = @import("../aarch64.zig"); | ||
| 1196 | const trace = @import("../../tracy.zig").trace; | ||
| 1197 | const Atom = @This(); | ||
| 1221 | const File = @import("file.zig").File; | 1198 | const File = @import("file.zig").File; |
| 1222 | const MachO = @import("../MachO.zig"); | 1199 | const MachO = @import("../MachO.zig"); |
| 1223 | const Object = @import("Object.zig"); | 1200 | const 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 { |
| 247 | pub fn addEntitlements(self: *CodeSignature, allocator: Allocator, path: []const u8) !void { | 247 | pub 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 | } |
| 253 | 253 | ||
| ... | @@ -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; |
| 305 | 305 | ||
| 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); |
| 312 | 313 | ||
| 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 | } |
| 317 | 318 | ||
| 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); |
| 324 | 326 | ||
| 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 { |
| 269 | 269 | ||
| 270 | fn writeLoadCommands(self: *DebugSymbols, macho_file: *MachO) !struct { usize, usize } { | 270 | fn 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(); | ||
| 278 | 274 | ||
| 279 | var ncmds: usize = 0; | 275 | var ncmds: usize = 0; |
| 280 | 276 | ||
| 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; |
| 285 | 281 | ||
| 286 | // Segment and section load commands | 282 | // 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 | } |
| 317 | 313 | ||
| 318 | try writer.writeStruct(self.symtab_cmd); | 314 | try bw.writeStruct(self.symtab_cmd); |
| 319 | ncmds += 1; | 315 | ncmds += 1; |
| 320 | 316 | ||
| 321 | assert(stream.pos == needed_size); | 317 | assert(bw.end == bw.buffer.len); |
| 322 | 318 | try self.file.?.pwriteAll(bw.buffer, @sizeOf(macho.mach_header_64)); | |
| 323 | try self.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); | ||
| 324 | 319 | ||
| 325 | return .{ ncmds, buffer.len }; | 320 | return .{ ncmds, bw.end }; |
| 326 | } | 321 | } |
| 327 | 322 | ||
| 328 | fn writeHeader(self: *DebugSymbols, macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { | 323 | fn 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; |
| 460 | const mem = std.mem; | 455 | const mem = std.mem; |
| 461 | const padToIdeal = MachO.padToIdeal; | 456 | const padToIdeal = MachO.padToIdeal; |
| 462 | const trace = @import("../../tracy.zig").trace; | 457 | const trace = @import("../../tracy.zig").trace; |
| 458 | const Writer = std.io.Writer; | ||
| 463 | 459 | ||
| 464 | const Allocator = mem.Allocator; | 460 | const Allocator = mem.Allocator; |
| 465 | const MachO = @import("../MachO.zig"); | 461 | const 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; |
| 87 | 87 | ||
| ... | @@ -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 | } |
| 182 | 182 | ||
| 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 | } |
| 187 | 187 | ||
| ... | @@ -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 | } |
| 274 | 274 | ||
| 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 | } |
| 290 | 280 | ||
| 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 { |
| 307 | 297 | ||
| 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; |
| 312 | 302 | ||
| 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 { |
| 323 | 313 | ||
| 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 | } |
| 341 | 331 | ||
| 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 | } |
| 349 | 337 | ||
| 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; |
| 63 | 63 | ||
| 64 | log.debug("parsing dylib from binary: {}", .{@as(Path, self.path)}); | 64 | log.debug("parsing dylib from binary: {f}", .{@as(Path, self.path)}); |
| 65 | 65 | ||
| 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 { |
| 140 | 140 | ||
| 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 that | 148 | // 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 first | 149 | // 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 | } |
| 160 | 160 | ||
| 161 | const 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 | |||
| 201 | pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void { | 161 | pub 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 |
| 207 | 167 | ||
| 208 | fn parseTrieNode( | 168 | fn 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 ordinal | 187 | _ = 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 offset | 191 | _ = try br.takeLeb128(u64); // stub offset |
| 232 | _ = try it.readUleb128(); // resolver offset | 192 | _ = 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 offset | 195 | _ = 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 | } |
| 239 | 199 | ||
| 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 | } |
| 252 | 211 | ||
| ... | @@ -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(); |
| 259 | 218 | ||
| 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 | } |
| 263 | 222 | ||
| 264 | fn parseTbd(self: *Dylib, macho_file: *MachO) !void { | 223 | fn 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 { |
| 267 | 226 | ||
| 268 | const gpa = macho_file.base.comp.gpa; | 227 | const gpa = macho_file.base.comp.gpa; |
| 269 | 228 | ||
| 270 | log.debug("parsing dylib from stub: {}", .{self.path}); | 229 | log.debug("parsing dylib from stub: {f}", .{self.path}); |
| 271 | 230 | ||
| 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 | } |
| 693 | 652 | ||
| 694 | pub fn format( | 653 | pub 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 | |||
| 707 | pub 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 | } |
| 713 | 659 | ||
| 714 | const FormatContext = struct { | 660 | const Format = struct { |
| 715 | dylib: *Dylib, | 661 | dylib: *Dylib, |
| 716 | macho_file: *MachO, | 662 | macho_file: *MachO, |
| 717 | }; | ||
| 718 | 663 | ||
| 719 | fn 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 | }; |
| 740 | 679 | ||
| 741 | pub const TargetMatcher = struct { | 680 | pub 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 | }; |
| 950 | 889 | ||
| 890 | const std = @import("std"); | ||
| 951 | const assert = std.debug.assert; | 891 | const assert = std.debug.assert; |
| 952 | const fat = @import("fat.zig"); | ||
| 953 | const fs = std.fs; | 892 | const fs = std.fs; |
| 954 | const fmt = std.fmt; | 893 | const fmt = std.fmt; |
| 955 | const log = std.log.scoped(.link); | 894 | const log = std.log.scoped(.link); |
| 956 | const macho = std.macho; | 895 | const macho = std.macho; |
| 957 | const math = std.math; | 896 | const math = std.math; |
| 958 | const mem = std.mem; | 897 | const mem = std.mem; |
| 959 | const tapi = @import("../tapi.zig"); | ||
| 960 | const trace = @import("../../tracy.zig").trace; | ||
| 961 | const std = @import("std"); | ||
| 962 | const Allocator = mem.Allocator; | 898 | const Allocator = mem.Allocator; |
| 963 | const Path = std.Build.Cache.Path; | 899 | const Path = std.Build.Cache.Path; |
| 900 | const Writer = std.io.Writer; | ||
| 964 | 901 | ||
| 965 | const Dylib = @This(); | 902 | const Dylib = @This(); |
| 966 | const File = @import("file.zig").File; | 903 | const File = @import("file.zig").File; |
| ... | @@ -969,3 +906,6 @@ const LoadCommandIterator = macho.LoadCommandIterator; | ... | @@ -969,3 +906,6 @@ const LoadCommandIterator = macho.LoadCommandIterator; |
| 969 | const MachO = @import("../MachO.zig"); | 906 | const MachO = @import("../MachO.zig"); |
| 970 | const Symbol = @import("Symbol.zig"); | 907 | const Symbol = @import("Symbol.zig"); |
| 971 | const Tbd = tapi.Tbd; | 908 | const Tbd = tapi.Tbd; |
| 909 | const fat = @import("fat.zig"); | ||
| 910 | const tapi = @import("../tapi.zig"); | ||
| 911 | const 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 |
| 261 | 261 | ||
| 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; |
| 265 | 265 | ||
| 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 | } |
| 838 | 838 | ||
| 839 | const FormatContext = struct { | 839 | const 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 | }; |
| 843 | 866 | ||
| 844 | pub fn fmtAtoms(self: *InternalObject, macho_file: *MachO) std.fmt.Formatter(formatAtoms) { | 867 | pub 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 | } |
| 850 | 873 | ||
| 851 | fn formatAtoms( | 874 | pub 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 | |||
| 866 | pub 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 | } |
| 872 | 880 | ||
| 873 | fn 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 | |||
| 895 | const Section = struct { | 881 | const 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; |
| 908 | const mem = std.mem; | 894 | const mem = std.mem; |
| 909 | const std = @import("std"); | 895 | const std = @import("std"); |
| 910 | const trace = @import("../../tracy.zig").trace; | 896 | const trace = @import("../../tracy.zig").trace; |
| 897 | const Writer = std.io.Writer; | ||
| 911 | 898 | ||
| 912 | const Allocator = std.mem.Allocator; | 899 | const Allocator = std.mem.Allocator; |
| 913 | const Atom = @import("Atom.zig"); | 900 | const 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(); |
| 74 | 74 | ||
| 75 | log.debug("parsing {}", .{self.fmtPath()}); | 75 | log.debug("parsing {f}", .{self.fmtPath()}); |
| 76 | 76 | ||
| 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 { |
| 239 | 239 | ||
| 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 that | 247 | // 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 first | 248 | // 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; |
| 309 | 309 | ||
| 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 atom | 366 | // 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 | } |
| 1067 | 1071 | ||
| 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 | } |
| 1696 | 1700 | ||
| 1697 | pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { | 1701 | pub fn writeAr(self: Object, bw: *Writer, ar_format: Archive.Format, macho_file: *MachO) !void { |
| 1698 | // Header | 1702 | // 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 | // Data | 1706 | // Data |
| 1703 | const file = macho_file.getFileHandle(self.file_handle); | 1707 | const file = macho_file.getFileHandle(self.file_handle); |
| 1704 | // TODO try using copyRangeAll | 1708 | // 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 | } |
| 1712 | 1716 | ||
| 1713 | pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void { | 1717 | pub 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); |
| 1866 | 1870 | ||
| 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 | } |
| 2514 | 2518 | ||
| 2515 | pub fn format( | 2519 | const 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 | |||
| 2528 | const 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 | }; |
| 2532 | 2580 | ||
| 2533 | pub fn fmtAtoms(self: *Object, macho_file: *MachO) std.fmt.Formatter(formatAtoms) { | 2581 | pub 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 | } |
| 2539 | 2587 | ||
| 2540 | fn formatAtoms( | 2588 | pub 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 | |||
| 2557 | pub 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 | } |
| 2563 | 2594 | ||
| 2564 | fn formatCies( | 2595 | pub 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 | |||
| 2579 | pub 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 | } |
| 2585 | 2601 | ||
| 2586 | fn formatFdes( | 2602 | pub 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 | |||
| 2601 | pub 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 | } |
| 2607 | 2608 | ||
| 2608 | fn formatUnwindRecords( | 2609 | pub 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 | |||
| 2624 | pub 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 | } |
| 2630 | 2615 | ||
| 2631 | fn 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 | |||
| 2663 | pub fn fmtPath(self: Object) std.fmt.Formatter(Object, formatPath) { | 2616 | pub fn fmtPath(self: Object) std.fmt.Formatter(Object, formatPath) { |
| 2664 | return .{ .data = self }; | 2617 | return .{ .data = self }; |
| 2665 | } | 2618 | } |
| 2666 | 2619 | ||
| 2667 | fn formatPath(object: Object, writer: *std.io.Writer) std.io.Writer.Error!void { | 2620 | fn 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 | } |
| 2676 | 2629 | ||
| ... | @@ -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 | } |
| 2726 | 2679 | ||
| 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 | } | ||
| 2739 | 2683 | ||
| 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 | }; | ||
| 2741 | 2696 | ||
| 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 | }; |
| 2766 | 2702 | ||
| ... | @@ -3150,17 +3086,18 @@ const aarch64 = struct { | ... | @@ -3150,17 +3086,18 @@ const aarch64 = struct { |
| 3150 | } | 3086 | } |
| 3151 | }; | 3087 | }; |
| 3152 | 3088 | ||
| 3089 | const std = @import("std"); | ||
| 3153 | const assert = std.debug.assert; | 3090 | const assert = std.debug.assert; |
| 3154 | const eh_frame = @import("eh_frame.zig"); | ||
| 3155 | const log = std.log.scoped(.link); | 3091 | const log = std.log.scoped(.link); |
| 3156 | const macho = std.macho; | 3092 | const macho = std.macho; |
| 3157 | const math = std.math; | 3093 | const math = std.math; |
| 3158 | const mem = std.mem; | 3094 | const mem = std.mem; |
| 3159 | const trace = @import("../../tracy.zig").trace; | ||
| 3160 | const std = @import("std"); | ||
| 3161 | const Path = std.Build.Cache.Path; | 3095 | const Path = std.Build.Cache.Path; |
| 3096 | const Allocator = std.mem.Allocator; | ||
| 3097 | const Writer = std.io.Writer; | ||
| 3162 | 3098 | ||
| 3163 | const Allocator = mem.Allocator; | 3099 | const eh_frame = @import("eh_frame.zig"); |
| 3100 | const trace = @import("../../tracy.zig").trace; | ||
| 3164 | const Archive = @import("Archive.zig"); | 3101 | const Archive = @import("Archive.zig"); |
| 3165 | const Atom = @import("Atom.zig"); | 3102 | const Atom = @import("Atom.zig"); |
| 3166 | const Cie = eh_frame.Cie; | 3103 | const 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 | } |
| 72 | 72 | ||
| 73 | const FormatCtx = struct { Relocation, std.Target.Cpu.Arch }; | 73 | pub fn fmtPretty(rel: Relocation, cpu_arch: std.Target.Cpu.Arch) std.fmt.Formatter(Format, Format.pretty) { |
| 74 | |||
| 75 | pub 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 | } |
| 78 | 76 | ||
| 79 | fn formatPretty( | 77 | const 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 | } | ||
| 124 | 118 | ||
| 125 | pub const Type = enum { | 119 | pub const Type = enum { |
| 126 | // x86_64 | 120 | // x86_64 |
| ... | @@ -164,10 +158,11 @@ pub const Type = enum { | ... | @@ -164,10 +158,11 @@ pub const Type = enum { |
| 164 | 158 | ||
| 165 | const Tag = enum { local, @"extern" }; | 159 | const Tag = enum { local, @"extern" }; |
| 166 | 160 | ||
| 161 | const std = @import("std"); | ||
| 167 | const assert = std.debug.assert; | 162 | const assert = std.debug.assert; |
| 168 | const macho = std.macho; | 163 | const macho = std.macho; |
| 169 | const math = std.math; | 164 | const math = std.math; |
| 170 | const std = @import("std"); | 165 | const Writer = std.io.Writer; |
| 171 | 166 | ||
| 172 | const Atom = @import("Atom.zig"); | 167 | const Atom = @import("Atom.zig"); |
| 173 | const MachO = @import("../MachO.zig"); | 168 | const 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 | } |
| 288 | 288 | ||
| 289 | pub fn format( | 289 | pub 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 | |||
| 302 | const FormatContext = struct { | ||
| 303 | symbol: Symbol, | ||
| 304 | macho_file: *MachO, | ||
| 305 | }; | ||
| 306 | |||
| 307 | pub 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 | } |
| 313 | 295 | ||
| 314 | fn format2( | 296 | const 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 | } | ||
| 354 | 334 | ||
| 355 | pub const Flags = packed struct { | 335 | pub 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; |
| 437 | const assert = std.debug.assert; | 417 | const assert = std.debug.assert; |
| 438 | const macho = std.macho; | 418 | const macho = std.macho; |
| 439 | const std = @import("std"); | 419 | const std = @import("std"); |
| 420 | const Writer = std.io.Writer; | ||
| 440 | 421 | ||
| 441 | const Atom = @import("Atom.zig"); | 422 | const Atom = @import("Atom.zig"); |
| 442 | const File = @import("file.zig").File; | 423 | const 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 | } |
| 22 | 22 | ||
| 23 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { | 23 | pub 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 | } |
| 35 | 35 | ||
| ... | @@ -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 | } |
| 63 | 63 | ||
| 64 | pub fn format( | 64 | pub 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 | |||
| 77 | pub 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 | } |
| 83 | 70 | ||
| 84 | const FormatContext = struct { | 71 | const Format = struct { |
| 85 | thunk: Thunk, | 72 | thunk: Thunk, |
| 86 | macho_file: *MachO, | 73 | macho_file: *MachO, |
| 87 | }; | ||
| 88 | 74 | ||
| 89 | fn 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 | }; |
| 105 | 85 | ||
| 106 | const trampoline_size = 3 * @sizeOf(u32); | 86 | const trampoline_size = 3 * @sizeOf(u32); |
| 107 | 87 | ||
| ... | @@ -115,6 +95,7 @@ const math = std.math; | ... | @@ -115,6 +95,7 @@ const math = std.math; |
| 115 | const mem = std.mem; | 95 | const mem = std.mem; |
| 116 | const std = @import("std"); | 96 | const std = @import("std"); |
| 117 | const trace = @import("../../tracy.zig").trace; | 97 | const trace = @import("../../tracy.zig").trace; |
| 98 | const Writer = std.io.Writer; | ||
| 118 | 99 | ||
| 119 | const Allocator = mem.Allocator; | 100 | const Allocator = mem.Allocator; |
| 120 | const Atom = @import("Atom.zig"); | 101 | const 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 | } |
| 208 | 208 | ||
| ... | @@ -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 | } |
| 257 | 257 | ||
| 258 | log.debug("{}", .{page.fmt(info.*)}); | 258 | log.debug("{f}", .{page.fmt(info.*)}); |
| 259 | 259 | ||
| 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 | } |
| 291 | 291 | ||
| 292 | pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { | 292 | pub 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.?]; |
| 295 | 295 | ||
| 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)); |
| 305 | 302 | ||
| 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 | }); |
| 314 | 311 | ||
| 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])); |
| 316 | 313 | ||
| 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 | } |
| 321 | 318 | ||
| 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 { |
| 335 | 332 | ||
| 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 { |
| 344 | 341 | ||
| 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 | } |
| 352 | 349 | ||
| 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 | } |
| 362 | 356 | ||
| 363 | @memset(buffer[stream.pos..], 0); | 357 | @memset(bw.unusedCapacitySlice(), 0); |
| 364 | } | 358 | } |
| 365 | 359 | ||
| 366 | fn getOrPutPersonalityFunction(info: *UnwindInfo, ref: MachO.Ref) error{TooManyPersonalities}!u2 { | 360 | fn 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 | } |
| 457 | 451 | ||
| 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 | }; |
| 469 | 457 | ||
| ... | @@ -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 | } |
| 519 | 507 | ||
| 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 | } |
| 539 | 514 | ||
| 540 | const FormatContext = struct { | 515 | const Format = struct { |
| 541 | rec: Record, | 516 | rec: Record, |
| 542 | macho_file: *MachO, | 517 | macho_file: *MachO, |
| 543 | }; | ||
| 544 | 518 | ||
| 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 | } | ||
| 562 | 530 | ||
| 563 | pub const Index = u32; | 531 | pub const Index = u32; |
| 564 | 532 | ||
| ... | @@ -613,45 +581,25 @@ const Page = struct { | ... | @@ -613,45 +581,25 @@ const Page = struct { |
| 613 | return null; | 581 | return null; |
| 614 | } | 582 | } |
| 615 | 583 | ||
| 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 | }; | ||
| 633 | 587 | ||
| 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 | }; |
| 653 | 601 | ||
| 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; |
| 720 | const math = std.math; | 668 | const math = std.math; |
| 721 | const mem = std.mem; | 669 | const mem = std.mem; |
| 722 | const trace = @import("../../tracy.zig").trace; | 670 | const trace = @import("../../tracy.zig").trace; |
| 671 | const Writer = std.io.Writer; | ||
| 723 | 672 | ||
| 724 | const Allocator = mem.Allocator; | 673 | const Allocator = mem.Allocator; |
| 725 | const Atom = @import("Atom.zig"); | 674 | const 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 | } |
| 319 | 319 | ||
| 320 | pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void { | 320 | pub fn writeAr(self: ZigObject, bw: *Writer, ar_format: Archive.Format) Writer.Error!void { |
| 321 | // Header | 321 | // 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 | // Data | 324 | // Data |
| 325 | try writer.writeAll(self.data.items); | 325 | try bw.writeAll(self.data.items); |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | pub fn claimUnresolved(self: *ZigObject, macho_file: *MachO) void { | 328 | pub 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( |
| 921 | 920 | ||
| 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); |
| 945 | 943 | ||
| 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 }); |
| 947 | 945 | ||
| 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); |
| 1025 | 1023 | ||
| 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 }); |
| 1027 | 1025 | ||
| 1028 | // 1. Lower TLV initializer | 1026 | // 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); |
| 1352 | 1350 | ||
| 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; |
| 1432 | 1430 | ||
| 1433 | log.debug("deleting export '{}'", .{name.fmt(&zcu.intern_pool)}); | 1431 | log.debug("deleting export '{f}'", .{name.fmt(&zcu.intern_pool)}); |
| 1434 | 1432 | ||
| 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 | } |
| 1680 | 1678 | ||
| 1681 | pub fn fmtSymtab(self: *ZigObject, macho_file: *MachO) std.fmt.Formatter(formatSymtab) { | 1679 | pub 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 | } |
| 1687 | 1685 | ||
| 1688 | const FormatContext = struct { | 1686 | const Format = struct { |
| 1689 | self: *ZigObject, | 1687 | self: *ZigObject, |
| 1690 | macho_file: *MachO, | 1688 | macho_file: *MachO, |
| 1691 | }; | ||
| 1692 | 1689 | ||
| 1693 | fn 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 | } | ||
| 1714 | 1704 | ||
| 1715 | pub 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 | |||
| 1716 | pub 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 | } |
| 1721 | 1722 | ||
| 1722 | fn 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 | |||
| 1739 | const AvMetadata = struct { | 1723 | const 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; |
| 1797 | const target_util = @import("../../target.zig"); | 1781 | const target_util = @import("../../target.zig"); |
| 1798 | const trace = @import("../../tracy.zig").trace; | 1782 | const trace = @import("../../tracy.zig").trace; |
| 1799 | const std = @import("std"); | 1783 | const std = @import("std"); |
| 1784 | const Writer = std.io.Writer; | ||
| 1800 | 1785 | ||
| 1801 | const Allocator = std.mem.Allocator; | 1786 | const Allocator = std.mem.Allocator; |
| 1802 | const Archive = @import("Archive.zig"); | 1787 | const 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 { |
| 117 | fn markLive(atom: *Atom, macho_file: *MachO) void { | 117 | fn 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 | } |
| 198 | 198 | ||
| 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 | }; |
| 210 | 204 | ||
| ... | @@ -219,6 +213,7 @@ const mem = std.mem; | ... | @@ -219,6 +213,7 @@ const mem = std.mem; |
| 219 | const trace = @import("../../tracy.zig").trace; | 213 | const trace = @import("../../tracy.zig").trace; |
| 220 | const track_live_log = std.log.scoped(.dead_strip_track_live); | 214 | const track_live_log = std.log.scoped(.dead_strip_track_live); |
| 221 | const std = @import("std"); | 215 | const std = @import("std"); |
| 216 | const Writer = std.io.Writer; | ||
| 222 | 217 | ||
| 223 | const Allocator = mem.Allocator; | 218 | const Allocator = mem.Allocator; |
| 224 | const Atom = @import("Atom.zig"); | 219 | const 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, |
| 3 | 3 | ||
| 4 | pub const Entry = struct { | 4 | pub const Entry = struct { |
| 5 | offset: u64, | 5 | offset: u64, |
| 6 | segment_id: u8, | 6 | segment_id: u4, |
| 7 | 7 | ||
| 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 { |
| 110 | fn finalize(rebase: *Rebase, gpa: Allocator) !void { | 110 | fn finalize(rebase: *Rebase, gpa: Allocator) !void { |
| 111 | if (rebase.entries.items.len == 0) return; | 111 | if (rebase.entries.items.len == 0) return; |
| 112 | 112 | ||
| 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(); | ||
| 114 | 116 | ||
| 115 | log.debug("rebase opcodes", .{}); | 117 | log.debug("rebase opcodes", .{}); |
| 116 | 118 | ||
| 117 | std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan); | 119 | std.mem.sort(Entry, rebase.entries.items, {}, Entry.lessThan); |
| 118 | 120 | ||
| 119 | try setTypePointer(writer); | 121 | try setTypePointer(bw); |
| 120 | 122 | ||
| 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 | } |
| 129 | 131 | ||
| 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 | } |
| 133 | 135 | ||
| 134 | fn finalizeSegment(entries: []const Entry, writer: anytype) !void { | 136 | fn finalizeSegment(entries: []const Entry, bw: *Writer) Writer.Error!void { |
| 135 | if (entries.len == 0) return; | 137 | if (entries.len == 0) return; |
| 136 | 138 | ||
| 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); |
| 140 | 142 | ||
| 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 | } |
| 220 | 222 | ||
| 221 | fn setTypePointer(writer: anytype) !void { | 223 | fn 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 | } |
| 225 | 227 | ||
| 226 | fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void { | 228 | fn 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 | } |
| 231 | 233 | ||
| 232 | fn rebaseAddAddr(addr: u64, writer: anytype) !void { | 234 | fn 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 | } |
| 237 | 239 | ||
| 238 | fn rebaseTimes(count: usize, writer: anytype) !void { | 240 | fn 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 | } |
| 247 | 249 | ||
| 248 | fn rebaseTimesSkip(count: usize, skip: u64, writer: anytype) !void { | 250 | fn 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 | } |
| 254 | 256 | ||
| 255 | fn addAddr(addr: u64, writer: anytype) !void { | 257 | fn 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 | } |
| 267 | 267 | ||
| 268 | fn done(writer: anytype) !void { | 268 | fn 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 | } |
| 272 | 272 | ||
| 273 | pub fn write(rebase: Rebase, writer: anytype) !void { | 273 | pub 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 | } |
| 276 | 276 | ||
| 277 | test "rebase - no entries" { | 277 | test "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); |
| 654 | const macho = std.macho; | 654 | const macho = std.macho; |
| 655 | const mem = std.mem; | 655 | const mem = std.mem; |
| 656 | const testing = std.testing; | 656 | const testing = std.testing; |
| 657 | const trace = @import("../../../tracy.zig").trace; | ||
| 658 | |||
| 659 | const Allocator = mem.Allocator; | 657 | const Allocator = mem.Allocator; |
| 658 | const Writer = std.io.Writer; | ||
| 659 | |||
| 660 | const trace = @import("../../../tracy.zig").trace; | ||
| 660 | const File = @import("../file.zig").File; | 661 | const File = @import("../file.zig").File; |
| 661 | const MachO = @import("../../MachO.zig"); | 662 | const MachO = @import("../../MachO.zig"); |
| 662 | const Rebase = @This(); | 663 | const Rebase = @This(); |
src/link/MachO/dyld_info/Trie.zig+32-37| ... | @@ -31,7 +31,7 @@ | ... | @@ -31,7 +31,7 @@ |
| 31 | 31 | ||
| 32 | /// The root node of the trie. | 32 | /// The root node of the trie. |
| 33 | root: ?Node.Index = null, | 33 | root: ?Node.Index = null, |
| 34 | buffer: std.ArrayListUnmanaged(u8) = .empty, | 34 | buffer: []u8 = &.{}, |
| 35 | nodes: std.MultiArrayList(Node) = .{}, | 35 | nodes: std.MultiArrayList(Node) = .{}, |
| 36 | edges: std.ArrayListUnmanaged(Edge) = .empty, | 36 | edges: std.ArrayListUnmanaged(Edge) = .empty, |
| 37 | 37 | ||
| ... | @@ -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 { |
| 123 | 123 | ||
| 124 | try self.finalize(gpa); | 124 | try self.finalize(gpa); |
| 125 | 125 | ||
| 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 | } |
| 128 | 128 | ||
| 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); |
| 140 | 140 | ||
| 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(); |
| 143 | 143 | ||
| 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 | } |
| 166 | 166 | ||
| 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 | } |
| 172 | 174 | ||
| ... | @@ -181,17 +183,17 @@ const FinalizeNodeResult = struct { | ... | @@ -181,17 +183,17 @@ const FinalizeNodeResult = struct { |
| 181 | 183 | ||
| 182 | /// Updates offset of this node in the output byte stream. | 184 | /// Updates offset of this node in the output byte stream. |
| 183 | fn finalizeNode(self: *Trie, node_index: Node.Index, offset_in_trie: u32) !FinalizeNodeResult { | 185 | fn 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(); |
| 187 | 189 | ||
| 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 nodes | 198 | 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 | } |
| 206 | 208 | ||
| 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); |
| 211 | 213 | ||
| 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 | } |
| 228 | 230 | ||
| 229 | pub fn write(self: Trie, writer: anytype) !void { | 231 | pub 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 | } |
| 233 | 234 | ||
| 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. |
| 240 | fn writeNode(self: *Trie, node_index: Node.Index, writer: anytype) !void { | 241 | fn 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]; |
| 246 | 247 | ||
| 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 and | 251 | 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); |
| 256 | 255 | 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)); |
| 271 | 264 | ||
| 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 | } |
| 280 | 273 | ||
| ... | @@ -414,8 +407,10 @@ const macho = std.macho; | ... | @@ -414,8 +407,10 @@ const macho = std.macho; |
| 414 | const mem = std.mem; | 407 | const mem = std.mem; |
| 415 | const std = @import("std"); | 408 | const std = @import("std"); |
| 416 | const testing = std.testing; | 409 | const testing = std.testing; |
| 417 | const trace = @import("../../../tracy.zig").trace; | 410 | const Writer = std.io.Writer; |
| 418 | 411 | ||
| 412 | const trace = @import("../../../tracy.zig").trace; | ||
| 413 | const DeprecatedLinearFifo = @import("../../../deprecated.zig").LinearFifo; | ||
| 419 | const Allocator = mem.Allocator; | 414 | const Allocator = mem.Allocator; |
| 420 | const MachO = @import("../../MachO.zig"); | 415 | const MachO = @import("../../MachO.zig"); |
| 421 | const Trie = @This(); | 416 | const Trie = @This(); |
src/link/MachO/dyld_info/bind.zig+155-187| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | pub const Entry = struct { | 1 | pub 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, |
| 6 | 6 | ||
| 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, |
| 22 | 22 | ||
| 23 | const Self = @This(); | 23 | pub fn deinit(bind: *Bind, gpa: Allocator) void { |
| 24 | 24 | 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 | } |
| 29 | 27 | ||
| 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(); |
| 33 | 31 | ||
| ... | @@ -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 | } |
| 89 | 81 | ||
| ... | @@ -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 | } |
| 108 | 97 | ||
| ... | @@ -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 | } |
| 127 | 113 | ||
| 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 | } |
| 131 | 117 | ||
| 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; |
| 134 | 120 | ||
| 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(); | ||
| 136 | 124 | ||
| 137 | log.debug("bind opcodes", .{}); | 125 | log.debug("bind opcodes", .{}); |
| 138 | 126 | ||
| 139 | std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan); | 127 | std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan); |
| 140 | 128 | ||
| 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 | } |
| 149 | 137 | ||
| 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 | } |
| 153 | 141 | ||
| 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; |
| 156 | 144 | ||
| 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); |
| 159 | 147 | ||
| 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; |
| 183 | 171 | ||
| 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 | }; |
| 197 | 185 | ||
| 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); |
| 201 | 189 | ||
| 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 | } |
| 207 | 195 | ||
| ... | @@ -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 { |
| 258 | 246 | ||
| 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 | } |
| 265 | 253 | ||
| 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 | }; |
| 270 | 258 | ||
| ... | @@ -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, |
| 274 | 262 | ||
| 275 | const Self = @This(); | 263 | pub fn deinit(bind: *WeakBind, gpa: Allocator) void { |
| 276 | 264 | 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 | } |
| 281 | 267 | ||
| 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(); |
| 285 | 271 | ||
| ... | @@ -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 | } |
| 341 | 321 | ||
| ... | @@ -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 | } |
| 361 | 338 | ||
| ... | @@ -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 | } |
| 380 | 354 | ||
| 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 | } |
| 384 | 358 | ||
| 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; |
| 387 | 361 | ||
| 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(); | ||
| 389 | 365 | ||
| 390 | log.debug("weak bind opcodes", .{}); | 366 | log.debug("weak bind opcodes", .{}); |
| 391 | 367 | ||
| 392 | std.mem.sort(Entry, self.entries.items, ctx, Entry.lessThan); | 368 | std.mem.sort(Entry, bind.entries.items, ctx, Entry.lessThan); |
| 393 | 369 | ||
| 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 | } |
| 402 | 378 | ||
| 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 | } |
| 406 | 382 | ||
| 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; |
| 409 | 385 | ||
| 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); |
| 412 | 388 | ||
| 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_DEFINITION | 415 | const flags: u8 = 0; // TODO NON_WEAK_DEFINITION |
| 440 | 416 | ||
| 441 | try setSymbol(name, flags, writer); | 417 | try setSymbol(name, flags, bw); |
| 442 | try setTypePointer(writer); | 418 | try setTypePointer(bw); |
| 443 | 419 | ||
| 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 | } |
| 449 | 425 | ||
| ... | @@ -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 { |
| 500 | 476 | ||
| 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 | } |
| 507 | 483 | ||
| 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 | }; |
| 512 | 488 | ||
| ... | @@ -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, |
| 517 | 493 | ||
| 518 | const Self = @This(); | 494 | pub fn deinit(bind: *LazyBind, gpa: Allocator) void { |
| 519 | 495 | 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 | } |
| 525 | 499 | ||
| 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(); |
| 529 | 503 | ||
| ... | @@ -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 | } |
| 550 | 521 | ||
| 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 | } |
| 554 | 525 | ||
| 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); |
| 557 | 528 | ||
| 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(); | ||
| 559 | 532 | ||
| 560 | log.debug("lazy bind opcodes", .{}); | 533 | log.debug("lazy bind opcodes", .{}); |
| 561 | 534 | ||
| 562 | var addend: i64 = 0; | 535 | var addend: i64 = 0; |
| 563 | 536 | ||
| 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)); |
| 566 | 539 | ||
| 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 | }; |
| 580 | 553 | ||
| 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); |
| 584 | 557 | ||
| 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 | } |
| 589 | 562 | ||
| 590 | try doBind(writer); | 563 | try doBind(bw); |
| 591 | try done(writer); | 564 | try done(bw); |
| 592 | } | 565 | } |
| 593 | } | 566 | } |
| 594 | 567 | ||
| 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 | }; |
| 599 | 572 | ||
| 600 | fn setSegmentOffset(segment_id: u8, offset: u64, writer: anytype) !void { | 573 | fn 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 | } |
| 605 | 578 | ||
| 606 | fn setSymbol(name: []const u8, flags: u8, writer: anytype) !void { | 579 | fn 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 | } |
| 612 | 585 | ||
| 613 | fn setTypePointer(writer: anytype) !void { | 586 | fn 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 | } |
| 617 | 590 | ||
| 618 | fn setDylibOrdinal(ordinal: i16, writer: anytype) !void { | 591 | fn 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 binding | 598 | 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 | } |
| 641 | 612 | ||
| 642 | fn setAddend(addend: i64, writer: anytype) !void { | 613 | fn 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 | } |
| 647 | 618 | ||
| 648 | fn doBind(writer: anytype) !void { | 619 | fn 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 | } |
| 652 | 623 | ||
| 653 | fn doBindAddAddr(addr: u64, writer: anytype) !void { | 624 | fn 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 | } |
| 667 | 634 | ||
| 668 | fn doBindTimesSkip(count: usize, skip: u64, writer: anytype) !void { | 635 | fn 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 | } |
| 674 | 641 | ||
| 675 | fn addAddr(addr: u64, writer: anytype) !void { | 642 | fn 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 | } |
| 680 | 647 | ||
| 681 | fn done(writer: anytype) !void { | 648 | fn 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 | } |
| 685 | 652 | ||
| 653 | const std = @import("std"); | ||
| 686 | const assert = std.debug.assert; | 654 | const assert = std.debug.assert; |
| 687 | const leb = std.leb; | 655 | const leb = std.leb; |
| 688 | const log = std.log.scoped(.link_dyld_info); | 656 | const log = std.log.scoped(.link_dyld_info); |
| 689 | const macho = std.macho; | 657 | const macho = std.macho; |
| 690 | const mem = std.mem; | 658 | const mem = std.mem; |
| 691 | const testing = std.testing; | 659 | const testing = std.testing; |
| 692 | const trace = @import("../../../tracy.zig").trace; | 660 | const Allocator = std.mem.Allocator; |
| 693 | const std = @import("std"); | 661 | const Writer = std.io.Writer; |
| 694 | 662 | ||
| 695 | const Allocator = mem.Allocator; | 663 | const trace = @import("../../../tracy.zig").trace; |
| 696 | const File = @import("../file.zig").File; | 664 | const File = @import("../file.zig").File; |
| 697 | const MachO = @import("../../MachO.zig"); | 665 | const MachO = @import("../../MachO.zig"); |
| 698 | const Symbol = @import("../Symbol.zig"); | 666 | const 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(); |
| 14 | 14 | ||
| 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); | ||
| 17 | 16 | ||
| 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? |
| 19 | 20 | ||
| 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 |
| 23 | 24 | _ = 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 | ||
| 28 | 25 | ||
| 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 error | 30 | @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 error | 36 | @panic("unexpected personality pointer encoding"); // TODO error |
| 40 | } | 37 | } |
| 41 | _ = try reader.readInt(u32, .little); // personality pointer | 38 | _ = 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 | } |
| 83 | 80 | ||
| 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 | } |
| 103 | 87 | ||
| 104 | const FormatContext = struct { | 88 | const Format = struct { |
| 105 | cie: Cie, | 89 | cie: Cie, |
| 106 | macho_file: *MachO, | 90 | macho_file: *MachO, |
| 107 | }; | ||
| 108 | 91 | ||
| 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 | } | ||
| 124 | 101 | ||
| 125 | pub const Index = u32; | 102 | pub const Index = u32; |
| 126 | 103 | ||
| ... | @@ -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(); |
| 150 | 127 | ||
| 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.?]; |
| 154 | 130 | ||
| 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 index | 137 | // 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)); |
| 166 | 147 | ||
| 167 | // Associate with a CIE | 148 | // 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 { |
| 183 | 163 | ||
| 184 | // Parse LSDA atom index if any | 164 | // 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 | } |
| 233 | 211 | ||
| 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 | } |
| 253 | 218 | ||
| 254 | const FormatContext = struct { | 219 | const Format = struct { |
| 255 | fde: Fde, | 220 | fde: Fde, |
| 256 | macho_file: *MachO, | 221 | macho_file: *MachO, |
| 257 | }; | ||
| 258 | 222 | ||
| 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 | } | ||
| 277 | 235 | ||
| 278 | pub const Index = u32; | 236 | pub const Index = u32; |
| 279 | }; | 237 | }; |
| 280 | 238 | ||
| 281 | pub const Iterator = struct { | 239 | pub const Iterator = struct { |
| 282 | data: []const u8, | 240 | reader: *std.io.Reader, |
| 283 | pos: u32 = 0, | ||
| 284 | 241 | ||
| 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 | }; |
| 290 | 247 | ||
| 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; |
| 293 | 250 | if (r.seek >= r.storageBuffer().len) return null; | |
| 294 | var stream = std.io.fixedBufferStream(it.data[it.pos..]); | ||
| 295 | const reader = stream.reader(); | ||
| 296 | 251 | ||
| 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"); |
| 299 | 254 | ||
| 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); |
| 307 | 262 | ||
| 308 | return record; | 263 | return record; |
| 309 | } | 264 | } |
| ... | @@ -545,6 +500,7 @@ const math = std.math; | ... | @@ -545,6 +500,7 @@ const math = std.math; |
| 545 | const mem = std.mem; | 500 | const mem = std.mem; |
| 546 | const std = @import("std"); | 501 | const std = @import("std"); |
| 547 | const trace = @import("../../tracy.zig").trace; | 502 | const trace = @import("../../tracy.zig").trace; |
| 503 | const Writer = std.io.Writer; | ||
| 548 | 504 | ||
| 549 | const Allocator = std.mem.Allocator; | 505 | const Allocator = std.mem.Allocator; |
| 550 | const Atom = @import("Atom.zig"); | 506 | const 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 | } |
| 16 | 16 | ||
| 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 | } |
| 25 | 25 | ||
| ... | @@ -321,11 +321,11 @@ pub const File = union(enum) { | ... | @@ -321,11 +321,11 @@ pub const File = union(enum) { |
| 321 | }; | 321 | }; |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 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 | } |
| 331 | 331 | ||
| ... | @@ -364,6 +364,7 @@ const log = std.log.scoped(.link); | ... | @@ -364,6 +364,7 @@ const log = std.log.scoped(.link); |
| 364 | const macho = std.macho; | 364 | const macho = std.macho; |
| 365 | const Allocator = std.mem.Allocator; | 365 | const Allocator = std.mem.Allocator; |
| 366 | const Path = std.Build.Cache.Path; | 366 | const Path = std.Build.Cache.Path; |
| 367 | const Writer = std.io.Writer; | ||
| 367 | 368 | ||
| 368 | const trace = @import("../../tracy.zig").trace; | 369 | const trace = @import("../../tracy.zig").trace; |
| 369 | const Archive = @import("Archive.zig"); | 370 | const 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; |
| 3 | const log = std.log.scoped(.link); | 3 | const log = std.log.scoped(.link); |
| 4 | const macho = std.macho; | 4 | const macho = std.macho; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const Writer = std.io.Writer; | ||
| 6 | 7 | ||
| 7 | const Allocator = mem.Allocator; | 8 | const Allocator = mem.Allocator; |
| 8 | const DebugSymbols = @import("DebugSymbols.zig"); | 9 | const 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 | } |
| 182 | 183 | ||
| 183 | pub fn writeDylinkerLC(writer: anytype) !void { | 184 | pub 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 | } |
| 201 | 199 | ||
| 202 | const WriteDylibLCCtx = struct { | 200 | const 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 | }; |
| 209 | 207 | ||
| 210 | pub fn writeDylibLC(ctx: WriteDylibLCCtx, writer: anytype) !void { | 208 | pub 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 | } |
| 234 | 229 | ||
| 235 | pub fn writeDylibIdLC(macho_file: *MachO, writer: anytype) !void { | 230 | pub 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 | } |
| 260 | 255 | ||
| 261 | pub fn writeRpathLC(rpath: []const u8, writer: anytype) !void { | 256 | pub 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 | } |
| 279 | 271 | ||
| 280 | pub fn writeVersionMinLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void { | 272 | pub 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 | } |
| 297 | 289 | ||
| 298 | pub fn writeBuildVersionLC(platform: MachO.Platform, sdk_version: ?std.SemanticVersion, writer: anytype) !void { | 290 | pub 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 | } |
| 32 | 32 | ||
| ... | @@ -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); |
| 63 | 63 | ||
| 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 | } |
| 67 | 67 | ||
| 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); |
| 127 | 127 | ||
| 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 | } |
| 131 | 131 | ||
| 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 | }; |
| 203 | 203 | ||
| 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 | } |
| 207 | 207 | ||
| 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(); | ||
| 212 | 210 | ||
| 213 | // Write magic | 211 | // Write magic |
| 214 | try writer.writeAll(Archive.ARMAG); | 212 | bw.writeAll(Archive.ARMAG) catch unreachable; |
| 215 | 213 | ||
| 216 | // Write symtab | 214 | // 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 | }; |
| 221 | 218 | ||
| 222 | // Write object files | 219 | // 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 | } |
| 232 | 225 | ||
| 233 | assert(buffer.items.len == total_size); | 226 | assert(bw.end == bw.buffer.len); |
| 234 | 227 | 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); | ||
| 237 | 229 | ||
| 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 | } |
| 674 | 666 | ||
| 675 | fn writeSectionsToFile(macho_file: *MachO) !void { | 667 | fn 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(); |
| 678 | 670 | ||
| ... | @@ -689,12 +681,8 @@ fn writeSectionsToFile(macho_file: *MachO) !void { | ... | @@ -689,12 +681,8 @@ fn writeSectionsToFile(macho_file: *MachO) !void { |
| 689 | 681 | ||
| 690 | fn writeLoadCommands(macho_file: *MachO) error{ LinkFailure, OutOfMemory }!struct { usize, usize } { | 682 | fn 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(); | ||
| 698 | 686 | ||
| 699 | var ncmds: usize = 0; | 687 | var ncmds: usize = 0; |
| 700 | 688 | ||
| ... | @@ -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 | } |
| 715 | 699 | ||
| 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; |
| 728 | 706 | ||
| 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 | } |
| 740 | 714 | ||
| 741 | assert(stream.pos == needed_size); | 715 | assert(bw.end == bw.buffer.len); |
| 742 | 716 | 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 | } |
| 747 | 719 | ||
| 748 | fn writeHeader(macho_file: *MachO, ncmds: usize, sizeofcmds: usize) !void { | 720 | fn 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; |
| 784 | const math = std.math; | 756 | const math = std.math; |
| 785 | const mem = std.mem; | 757 | const mem = std.mem; |
| 786 | const state_log = std.log.scoped(.link_state); | 758 | const state_log = std.log.scoped(.link_state); |
| 759 | const Writer = std.io.Writer; | ||
| 787 | 760 | ||
| 788 | const Archive = @import("Archive.zig"); | 761 | const Archive = @import("Archive.zig"); |
| 789 | const Atom = @import("Atom.zig"); | 762 | const 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 | } |
| 29 | 29 | ||
| 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 | } |
| 39 | 39 | ||
| 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 | }; |
| 44 | 57 | ||
| 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 | }; |
| 69 | 62 | ||
| 70 | pub const StubsSection = struct { | 63 | pub 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 | } |
| 98 | 91 | ||
| 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 possible | 108 | // 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 | } |
| 130 | 123 | ||
| 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 | } |
| 139 | 127 | ||
| 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 | }; |
| 160 | 146 | ||
| 161 | pub const StubsHelperSection = struct { | 147 | pub 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 | } |
| 191 | 177 | ||
| 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(); |
| 195 | 181 | ||
| 196 | try stubs_helper.writePreamble(macho_file, writer); | 182 | try stubs_helper.writePreamble(macho_file, bw); |
| 197 | 183 | ||
| 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))) orelse | 212 | 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 | } |
| 236 | 222 | ||
| 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 possible | 246 | // 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 possible | 259 | // 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 | } |
| 295 | 281 | ||
| 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 | } |
| 345 | 331 | ||
| 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(); |
| 349 | 335 | ||
| 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 | } |
| 359 | 345 | ||
| 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 | } |
| 368 | 349 | ||
| 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 | }; |
| 389 | 368 | ||
| 390 | pub const ObjcStubsSection = struct { | 369 | pub 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 | } |
| 423 | 402 | ||
| 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(); |
| 427 | 406 | ||
| ... | @@ -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 | } |
| 484 | 463 | ||
| 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 | } |
| 493 | 467 | ||
| 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 | }; |
| 513 | 485 | ||
| 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 | } |
| 526 | 498 | ||
| 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(); |
| 530 | 502 | ||
| ... | @@ -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 | } |
| 539 | 511 | ||
| 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 | } |
| 546 | 518 | ||
| 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 | } |
| 603 | 575 | ||
| 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().vmaddr | 578 | macho_file.getTextSegment().vmaddr |
| 607 | else | 579 | 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 | }; |
| 627 | 599 | ||
| 600 | const std = @import("std"); | ||
| 628 | const aarch64 = @import("../aarch64.zig"); | 601 | const aarch64 = @import("../aarch64.zig"); |
| 629 | const assert = std.debug.assert; | 602 | const assert = std.debug.assert; |
| 630 | const macho = std.macho; | 603 | const macho = std.macho; |
| 631 | const math = std.math; | 604 | const math = std.math; |
| 632 | const std = @import("std"); | ||
| 633 | const trace = @import("../../tracy.zig").trace; | ||
| 634 | |||
| 635 | const Allocator = std.mem.Allocator; | 605 | const Allocator = std.mem.Allocator; |
| 606 | const Writer = std.io.Writer; | ||
| 607 | |||
| 608 | const trace = @import("../../tracy.zig").trace; | ||
| 636 | const MachO = @import("../MachO.zig"); | 609 | const MachO = @import("../MachO.zig"); |
| 637 | const Symbol = @import("Symbol.zig"); | 610 | const Symbol = @import("Symbol.zig"); |