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");