master
  1value: u64 = 0,
  2out_n_sect: u8 = 0,
  3symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .empty,
  4output_symtab_ctx: MachO.SymtabCtx = .{},
  5
  6pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
  7    thunk.symbols.deinit(allocator);
  8}
  9
 10pub fn size(thunk: Thunk) usize {
 11    return thunk.symbols.keys().len * trampoline_size;
 12}
 13
 14pub fn getAddress(thunk: Thunk, macho_file: *MachO) u64 {
 15    const header = macho_file.sections.items(.header)[thunk.out_n_sect];
 16    return header.addr + thunk.value;
 17}
 18
 19pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
 20    return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;
 21}
 22
 23pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
 24    const Instruction = aarch64.encoding.Instruction;
 25    for (thunk.symbols.keys(), 0..) |ref, i| {
 26        const sym = ref.getSymbol(macho_file).?;
 27        const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
 28        const taddr = sym.getAddress(.{}, macho_file);
 29        const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
 30        try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
 31        try writer.writeInt(u32, @bitCast(
 32            Instruction.add(.x16, .x16, .{ .immediate = @truncate(taddr) }),
 33        ), .little);
 34        try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
 35    }
 36}
 37
 38pub fn calcSymtabSize(thunk: *Thunk, macho_file: *MachO) void {
 39    thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
 40    for (thunk.symbols.keys()) |ref| {
 41        const sym = ref.getSymbol(macho_file).?;
 42        thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + "__thunk".len + 1));
 43    }
 44}
 45
 46pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void {
 47    var n_strx = thunk.output_symtab_ctx.stroff;
 48    for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
 49        const sym = ref.getSymbol(macho_file).?;
 50        const name = sym.getName(macho_file);
 51        const out_sym = &ctx.symtab.items[ilocal];
 52        out_sym.n_strx = n_strx;
 53        @memcpy(ctx.strtab.items[n_strx..][0..name.len], name);
 54        n_strx += @intCast(name.len);
 55        @memcpy(ctx.strtab.items[n_strx..][0.."__thunk".len], "__thunk");
 56        n_strx += @intCast("__thunk".len);
 57        ctx.strtab.items[n_strx] = 0;
 58        n_strx += 1;
 59        out_sym.n_type = .{ .bits = .{ .ext = false, .type = .sect, .pext = false, .is_stab = 0 } };
 60        out_sym.n_sect = @intCast(thunk.out_n_sect + 1);
 61        out_sym.n_value = @intCast(thunk.getTargetAddress(ref, macho_file));
 62        out_sym.n_desc = @bitCast(@as(u16, 0));
 63    }
 64}
 65
 66pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Alt(Format, Format.default) {
 67    return .{ .data = .{
 68        .thunk = thunk,
 69        .macho_file = macho_file,
 70    } };
 71}
 72
 73const Format = struct {
 74    thunk: Thunk,
 75    macho_file: *MachO,
 76
 77    fn default(f: Format, w: *Writer) Writer.Error!void {
 78        const thunk = f.thunk;
 79        const macho_file = f.macho_file;
 80        try w.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
 81        for (thunk.symbols.keys()) |ref| {
 82            const sym = ref.getSymbol(macho_file).?;
 83            try w.print("  {f} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
 84        }
 85    }
 86};
 87
 88const trampoline_size = 3 * @sizeOf(u32);
 89
 90pub const Index = u32;
 91
 92const aarch64 = @import("../aarch64.zig");
 93const assert = std.debug.assert;
 94const log = std.log.scoped(.link);
 95const macho = std.macho;
 96const math = std.math;
 97const mem = std.mem;
 98const std = @import("std");
 99const trace = @import("../../tracy.zig").trace;
100const Writer = std.Io.Writer;
101
102const Allocator = mem.Allocator;
103const Atom = @import("Atom.zig");
104const MachO = @import("../MachO.zig");
105const Relocation = @import("Relocation.zig");
106const Symbol = @import("Symbol.zig");
107
108const Thunk = @This();