master
1pub const GotSection = struct {
2 symbols: std.ArrayList(MachO.Ref) = .empty,
3
4 pub const Index = u32;
5
6 pub fn deinit(got: *GotSection, allocator: Allocator) void {
7 got.symbols.deinit(allocator);
8 }
9
10 pub fn addSymbol(got: *GotSection, ref: MachO.Ref, macho_file: *MachO) !void {
11 const gpa = macho_file.base.comp.gpa;
12 const index = @as(Index, @intCast(got.symbols.items.len));
13 const entry = try got.symbols.addOne(gpa);
14 entry.* = ref;
15 const symbol = ref.getSymbol(macho_file).?;
16 symbol.setSectionFlags(.{ .has_got = true });
17 symbol.addExtra(.{ .got = index }, macho_file);
18 }
19
20 pub fn getAddress(got: GotSection, index: Index, macho_file: *MachO) u64 {
21 assert(index < got.symbols.items.len);
22 const header = macho_file.sections.items(.header)[macho_file.got_sect_index.?];
23 return header.addr + index * @sizeOf(u64);
24 }
25
26 pub fn size(got: GotSection) usize {
27 return got.symbols.items.len * @sizeOf(u64);
28 }
29
30 pub fn write(got: GotSection, macho_file: *MachO, writer: *Writer) !void {
31 const tracy = trace(@src());
32 defer tracy.end();
33 for (got.symbols.items) |ref| {
34 const sym = ref.getSymbol(macho_file).?;
35 const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file);
36 try writer.writeInt(u64, value, .little);
37 }
38 }
39
40 const Format = struct {
41 got: GotSection,
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 }
56 };
57
58 pub fn fmt(got: GotSection, macho_file: *MachO) std.fmt.Alt(Format, Format.print) {
59 return .{ .data = .{ .got = got, .macho_file = macho_file } };
60 }
61};
62
63pub const StubsSection = struct {
64 symbols: std.ArrayList(MachO.Ref) = .empty,
65
66 pub const Index = u32;
67
68 pub fn deinit(stubs: *StubsSection, allocator: Allocator) void {
69 stubs.symbols.deinit(allocator);
70 }
71
72 pub fn addSymbol(stubs: *StubsSection, ref: MachO.Ref, macho_file: *MachO) !void {
73 const gpa = macho_file.base.comp.gpa;
74 const index = @as(Index, @intCast(stubs.symbols.items.len));
75 const entry = try stubs.symbols.addOne(gpa);
76 entry.* = ref;
77 const symbol = ref.getSymbol(macho_file).?;
78 symbol.addExtra(.{ .stubs = index }, macho_file);
79 }
80
81 pub fn getAddress(stubs: StubsSection, index: Index, macho_file: *MachO) u64 {
82 assert(index < stubs.symbols.items.len);
83 const header = macho_file.sections.items(.header)[macho_file.stubs_sect_index.?];
84 return header.addr + index * header.reserved2;
85 }
86
87 pub fn size(stubs: StubsSection, macho_file: *MachO) usize {
88 const header = macho_file.sections.items(.header)[macho_file.stubs_sect_index.?];
89 return stubs.symbols.items.len * header.reserved2;
90 }
91
92 pub fn write(stubs: StubsSection, macho_file: *MachO, writer: *Writer) !void {
93 const tracy = trace(@src());
94 defer tracy.end();
95 const cpu_arch = macho_file.getTarget().cpu.arch;
96 const laptr_sect = macho_file.sections.items(.header)[macho_file.la_symbol_ptr_sect_index.?];
97
98 for (stubs.symbols.items, 0..) |ref, idx| {
99 const sym = ref.getSymbol(macho_file).?;
100 const source = sym.getAddress(.{ .stubs = true }, macho_file);
101 const target = laptr_sect.addr + idx * @sizeOf(u64);
102 switch (cpu_arch) {
103 .x86_64 => {
104 try writer.writeAll(&.{ 0xff, 0x25 });
105 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
106 },
107 .aarch64 => {
108 const Instruction = aarch64.encoding.Instruction;
109 // TODO relax if possible
110 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
111 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
112 try writer.writeInt(u32, @bitCast(Instruction.ldr(
113 .x16,
114 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } },
115 )), .little);
116 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
117 },
118 else => unreachable,
119 }
120 }
121 }
122
123 pub fn fmt(stubs: StubsSection, macho_file: *MachO) std.fmt.Alt(Format, Format.print) {
124 return .{ .data = .{ .stubs = stubs, .macho_file = macho_file } };
125 }
126
127 const Format = struct {
128 stubs: StubsSection,
129 macho_file: *MachO,
130
131 pub fn print(f: Format, w: *Writer) Writer.Error!void {
132 for (f.stubs.symbols.items, 0..) |ref, i| {
133 const symbol = ref.getSymbol(f.macho_file).?;
134 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
135 i,
136 symbol.getStubsAddress(f.macho_file),
137 ref,
138 symbol.getAddress(.{}, f.macho_file),
139 symbol.getName(f.macho_file),
140 });
141 }
142 }
143 };
144};
145
146pub const StubsHelperSection = struct {
147 pub inline fn preambleSize(cpu_arch: std.Target.Cpu.Arch) usize {
148 return switch (cpu_arch) {
149 .x86_64 => 16,
150 .aarch64 => 6 * @sizeOf(u32),
151 else => 0,
152 };
153 }
154
155 pub inline fn entrySize(cpu_arch: std.Target.Cpu.Arch) usize {
156 return switch (cpu_arch) {
157 .x86_64 => 10,
158 .aarch64 => 3 * @sizeOf(u32),
159 else => 0,
160 };
161 }
162
163 pub fn size(stubs_helper: StubsHelperSection, macho_file: *MachO) usize {
164 const tracy = trace(@src());
165 defer tracy.end();
166 _ = stubs_helper;
167 const cpu_arch = macho_file.getTarget().cpu.arch;
168 var s: usize = preambleSize(cpu_arch);
169 for (macho_file.stubs.symbols.items) |ref| {
170 const sym = ref.getSymbol(macho_file).?;
171 if (sym.flags.weak) continue;
172 s += entrySize(cpu_arch);
173 }
174 return s;
175 }
176
177 pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: *Writer) !void {
178 const tracy = trace(@src());
179 defer tracy.end();
180
181 try stubs_helper.writePreamble(macho_file, writer);
182
183 const cpu_arch = macho_file.getTarget().cpu.arch;
184 const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
185 const preamble_size = preambleSize(cpu_arch);
186 const entry_size = entrySize(cpu_arch);
187
188 var idx: usize = 0;
189 for (macho_file.stubs.symbols.items) |ref| {
190 const sym = ref.getSymbol(macho_file).?;
191 if (sym.flags.weak) continue;
192 const offset = macho_file.lazy_bind_section.offsets.items[idx];
193 const source: i64 = @intCast(sect.addr + preamble_size + entry_size * idx);
194 const target: i64 = @intCast(sect.addr);
195 switch (cpu_arch) {
196 .x86_64 => {
197 try writer.writeByte(0x68);
198 try writer.writeInt(u32, offset, .little);
199 try writer.writeByte(0xe9);
200 try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);
201 },
202 .aarch64 => {
203 const Instruction = aarch64.encoding.Instruction;
204 if (entry_size % Instruction.size != 0) return error.UnexpectedRemainder;
205 try writer.writeInt(u32, @bitCast(
206 Instruction.ldr(.w16, .{ .literal = std.math.cast(i21, entry_size - Instruction.size) orelse
207 return error.Overflow }),
208 ), .little);
209 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse
210 return error.Overflow;
211 try writer.writeInt(u32, @bitCast(Instruction.b(disp)), .little);
212 try writer.writeInt(u32, @bitCast(Instruction.udf(0x0)), .little);
213 },
214 else => unreachable,
215 }
216 idx += 1;
217 }
218 }
219
220 fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: *Writer) !void {
221 _ = stubs_helper;
222 const obj = macho_file.getInternalObject().?;
223 const cpu_arch = macho_file.getTarget().cpu.arch;
224 const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
225 const dyld_private_addr = target: {
226 const sym = obj.getDyldPrivateRef(macho_file).?.getSymbol(macho_file).?;
227 break :target sym.getAddress(.{}, macho_file);
228 };
229 const dyld_stub_binder_addr = target: {
230 const sym = obj.getDyldStubBinderRef(macho_file).?.getSymbol(macho_file).?;
231 break :target sym.getGotAddress(macho_file);
232 };
233 switch (cpu_arch) {
234 .x86_64 => {
235 try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d });
236 try writer.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little);
237 try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
238 try writer.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little);
239 try writer.writeByte(0x90);
240 },
241 .aarch64 => {
242 const Instruction = aarch64.encoding.Instruction;
243 {
244 // TODO relax if possible
245 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));
246 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x17, pages << 12)), .little);
247 try writer.writeInt(Instruction.Backing, @bitCast(
248 Instruction.add(.x17, .x17, .{ .immediate = @as(u12, @truncate(dyld_private_addr)) }),
249 ), .little);
250 }
251 try writer.writeInt(Instruction.Backing, @bitCast(
252 Instruction.stp(.x16, .x17, .{ .pre_index = .{ .base = .sp, .index = -16 } }),
253 ), .little);
254 {
255 // TODO relax if possible
256 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));
257 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
258 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.ldr(
259 .x16,
260 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(dyld_stub_binder_addr)) } },
261 )), .little);
262 }
263 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.br(.x16)), .little);
264 },
265 else => unreachable,
266 }
267 }
268};
269
270pub const LaSymbolPtrSection = struct {
271 pub fn size(laptr: LaSymbolPtrSection, macho_file: *MachO) usize {
272 _ = laptr;
273 return macho_file.stubs.symbols.items.len * @sizeOf(u64);
274 }
275
276 pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: *Writer) !void {
277 const tracy = trace(@src());
278 defer tracy.end();
279 _ = laptr;
280 const cpu_arch = macho_file.getTarget().cpu.arch;
281 const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?];
282 var stub_helper_idx: u32 = 0;
283 for (macho_file.stubs.symbols.items) |ref| {
284 const sym = ref.getSymbol(macho_file).?;
285 if (sym.flags.weak) {
286 const value = sym.getAddress(.{ .stubs = false }, macho_file);
287 try writer.writeInt(u64, @intCast(value), .little);
288 } else {
289 const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) +
290 StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx;
291 stub_helper_idx += 1;
292 try writer.writeInt(u64, @intCast(value), .little);
293 }
294 }
295 }
296};
297
298pub const TlvPtrSection = struct {
299 symbols: std.ArrayList(MachO.Ref) = .empty,
300
301 pub const Index = u32;
302
303 pub fn deinit(tlv: *TlvPtrSection, allocator: Allocator) void {
304 tlv.symbols.deinit(allocator);
305 }
306
307 pub fn addSymbol(tlv: *TlvPtrSection, ref: MachO.Ref, macho_file: *MachO) !void {
308 const gpa = macho_file.base.comp.gpa;
309 const index = @as(Index, @intCast(tlv.symbols.items.len));
310 const entry = try tlv.symbols.addOne(gpa);
311 entry.* = ref;
312 const symbol = ref.getSymbol(macho_file).?;
313 symbol.addExtra(.{ .tlv_ptr = index }, macho_file);
314 }
315
316 pub fn getAddress(tlv: TlvPtrSection, index: Index, macho_file: *MachO) u64 {
317 assert(index < tlv.symbols.items.len);
318 const header = macho_file.sections.items(.header)[macho_file.tlv_ptr_sect_index.?];
319 return header.addr + index * @sizeOf(u64);
320 }
321
322 pub fn size(tlv: TlvPtrSection) usize {
323 return tlv.symbols.items.len * @sizeOf(u64);
324 }
325
326 pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: *Writer) !void {
327 const tracy = trace(@src());
328 defer tracy.end();
329
330 for (tlv.symbols.items) |ref| {
331 const sym = ref.getSymbol(macho_file).?;
332 if (sym.flags.import) {
333 try writer.writeInt(u64, 0, .little);
334 } else {
335 try writer.writeInt(u64, sym.getAddress(.{}, macho_file), .little);
336 }
337 }
338 }
339
340 pub fn fmt(tlv: TlvPtrSection, macho_file: *MachO) std.fmt.Alt(Format, Format.print) {
341 return .{ .data = .{ .tlv = tlv, .macho_file = macho_file } };
342 }
343
344 const Format = struct {
345 tlv: TlvPtrSection,
346 macho_file: *MachO,
347
348 pub fn print(f: Format, w: *Writer) Writer.Error!void {
349 for (f.tlv.symbols.items, 0..) |ref, i| {
350 const symbol = ref.getSymbol(f.macho_file).?;
351 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
352 i,
353 symbol.getTlvPtrAddress(f.macho_file),
354 ref,
355 symbol.getAddress(.{}, f.macho_file),
356 symbol.getName(f.macho_file),
357 });
358 }
359 }
360 };
361};
362
363pub const ObjcStubsSection = struct {
364 symbols: std.ArrayList(MachO.Ref) = .empty,
365
366 pub fn deinit(objc: *ObjcStubsSection, allocator: Allocator) void {
367 objc.symbols.deinit(allocator);
368 }
369
370 pub fn entrySize(cpu_arch: std.Target.Cpu.Arch) u8 {
371 return switch (cpu_arch) {
372 .x86_64 => 13,
373 .aarch64 => 8 * @sizeOf(u32),
374 else => unreachable,
375 };
376 }
377
378 pub fn addSymbol(objc: *ObjcStubsSection, ref: MachO.Ref, macho_file: *MachO) !void {
379 const gpa = macho_file.base.comp.gpa;
380 const index = @as(Index, @intCast(objc.symbols.items.len));
381 const entry = try objc.symbols.addOne(gpa);
382 entry.* = ref;
383 const symbol = ref.getSymbol(macho_file).?;
384 symbol.addExtra(.{ .objc_stubs = index }, macho_file);
385 }
386
387 pub fn getAddress(objc: ObjcStubsSection, index: Index, macho_file: *MachO) u64 {
388 assert(index < objc.symbols.items.len);
389 const header = macho_file.sections.items(.header)[macho_file.objc_stubs_sect_index.?];
390 return header.addr + index * entrySize(macho_file.getTarget().cpu.arch);
391 }
392
393 pub fn size(objc: ObjcStubsSection, macho_file: *MachO) usize {
394 return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch);
395 }
396
397 pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: *Writer) !void {
398 const tracy = trace(@src());
399 defer tracy.end();
400
401 const obj = macho_file.getInternalObject().?;
402
403 for (objc.symbols.items, 0..) |ref, idx| {
404 const sym = ref.getSymbol(macho_file).?;
405 const addr = objc.getAddress(@intCast(idx), macho_file);
406 switch (macho_file.getTarget().cpu.arch) {
407 .x86_64 => {
408 try writer.writeAll(&.{ 0x48, 0x8b, 0x35 });
409 {
410 const target = sym.getObjcSelrefsAddress(macho_file);
411 const source = addr;
412 try writer.writeInt(i32, @intCast(target - source - 3 - 4), .little);
413 }
414 try writer.writeAll(&.{ 0xff, 0x25 });
415 {
416 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
417 const target = target_sym.getGotAddress(macho_file);
418 const source = addr + 7;
419 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
420 }
421 },
422 .aarch64 => {
423 const Instruction = aarch64.encoding.Instruction;
424 {
425 const target = sym.getObjcSelrefsAddress(macho_file);
426 const source = addr;
427 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
428 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x1, pages << 12)), .little);
429 try writer.writeInt(u32, @bitCast(Instruction.ldr(
430 .x1,
431 .{ .unsigned_offset = .{ .base = .x1, .offset = @as(u12, @truncate(target)) } },
432 )), .little);
433 }
434 {
435 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
436 const target = target_sym.getGotAddress(macho_file);
437 const source = addr + 2 * @sizeOf(u32);
438 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
439 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
440 try writer.writeInt(u32, @bitCast(Instruction.ldr(
441 .x16,
442 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } },
443 )), .little);
444 }
445 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
446 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
447 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
448 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
449 },
450 else => unreachable,
451 }
452 }
453 }
454
455 pub fn fmt(objc: ObjcStubsSection, macho_file: *MachO) std.fmt.Alt(Format, Format.print) {
456 return .{ .data = .{ .objc = objc, .macho_file = macho_file } };
457 }
458
459 const Format = struct {
460 objc: ObjcStubsSection,
461 macho_file: *MachO,
462
463 pub fn print(f: Format, w: *Writer) Writer.Error!void {
464 for (f.objc.symbols.items, 0..) |ref, i| {
465 const symbol = ref.getSymbol(f.macho_file).?;
466 try w.print(" {d}@0x{x} => {f}@0x{x} ({s})\n", .{
467 i,
468 symbol.getObjcStubsAddress(f.macho_file),
469 ref,
470 symbol.getAddress(.{}, f.macho_file),
471 symbol.getName(f.macho_file),
472 });
473 }
474 }
475 };
476
477 pub const Index = u32;
478};
479
480pub const Indsymtab = struct {
481 pub inline fn nsyms(ind: Indsymtab, macho_file: *MachO) u32 {
482 _ = ind;
483 return @intCast(macho_file.stubs.symbols.items.len * 2 + macho_file.got.symbols.items.len);
484 }
485
486 pub fn updateSize(ind: *Indsymtab, macho_file: *MachO) !void {
487 macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file);
488 }
489
490 pub fn write(ind: Indsymtab, macho_file: *MachO, writer: *Writer) !void {
491 const tracy = trace(@src());
492 defer tracy.end();
493
494 _ = ind;
495
496 for (macho_file.stubs.symbols.items) |ref| {
497 const sym = ref.getSymbol(macho_file).?;
498 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
499 try writer.writeInt(u32, idx, .little);
500 }
501 }
502
503 for (macho_file.got.symbols.items) |ref| {
504 const sym = ref.getSymbol(macho_file).?;
505 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
506 try writer.writeInt(u32, idx, .little);
507 }
508 }
509
510 for (macho_file.stubs.symbols.items) |ref| {
511 const sym = ref.getSymbol(macho_file).?;
512 if (sym.getOutputSymtabIndex(macho_file)) |idx| {
513 try writer.writeInt(u32, idx, .little);
514 }
515 }
516 }
517};
518
519pub const DataInCode = struct {
520 entries: std.ArrayList(Entry) = .empty,
521
522 pub fn deinit(dice: *DataInCode, allocator: Allocator) void {
523 dice.entries.deinit(allocator);
524 }
525
526 pub fn size(dice: DataInCode) usize {
527 return dice.entries.items.len * @sizeOf(macho.data_in_code_entry);
528 }
529
530 pub fn updateSize(dice: *DataInCode, macho_file: *MachO) !void {
531 const gpa = macho_file.base.comp.gpa;
532
533 for (macho_file.objects.items) |index| {
534 const object = macho_file.getFile(index).?.object;
535 const dices = object.getDataInCode();
536
537 try dice.entries.ensureUnusedCapacity(gpa, dices.len);
538
539 var next_dice: usize = 0;
540 for (object.getAtoms()) |atom_index| {
541 if (next_dice >= dices.len) break;
542 const atom = object.getAtom(atom_index) orelse continue;
543 const start_off = atom.getInputAddress(macho_file);
544 const end_off = start_off + atom.size;
545 const start_dice = next_dice;
546
547 if (end_off < dices[next_dice].offset) continue;
548
549 while (next_dice < dices.len and
550 dices[next_dice].offset < end_off) : (next_dice += 1)
551 {}
552
553 if (atom.isAlive()) for (dices[start_dice..next_dice]) |d| {
554 dice.entries.appendAssumeCapacity(.{
555 .atom_ref = .{ .index = atom_index, .file = index },
556 .offset = @intCast(d.offset - start_off),
557 .length = d.length,
558 .kind = d.kind,
559 });
560 };
561 }
562 }
563
564 macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow;
565 }
566
567 pub fn write(dice: DataInCode, macho_file: *MachO, writer: *Writer) !void {
568 const base_address = if (!macho_file.base.isRelocatable())
569 macho_file.getTextSegment().vmaddr
570 else
571 0;
572 for (dice.entries.items) |entry| {
573 const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file);
574 const offset = atom_address + entry.offset - base_address;
575 try writer.writeStruct(@as(macho.data_in_code_entry, .{
576 .offset = @intCast(offset),
577 .length = entry.length,
578 .kind = entry.kind,
579 }), .little);
580 }
581 }
582
583 const Entry = struct {
584 atom_ref: MachO.Ref,
585 offset: u32,
586 length: u16,
587 kind: u16,
588 };
589};
590
591const std = @import("std");
592const aarch64 = @import("../aarch64.zig");
593const assert = std.debug.assert;
594const macho = std.macho;
595const math = std.math;
596const Allocator = std.mem.Allocator;
597const Writer = std.Io.Writer;
598
599const trace = @import("../../tracy.zig").trace;
600const MachO = @import("../MachO.zig");
601const Symbol = @import("Symbol.zig");