aboutsummaryrefslogtreecommitdiff
path: root/src/link/MachO/Thunk.zig
blob: cdb9eb649af4a0aeb340d96cad81716cc66ecbde (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
value: u64 = 0,
out_n_sect: u8 = 0,
symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .empty,
output_symtab_ctx: MachO.SymtabCtx = .{},

pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
    thunk.symbols.deinit(allocator);
}

pub fn size(thunk: Thunk) usize {
    return thunk.symbols.keys().len * trampoline_size;
}

pub fn getAddress(thunk: Thunk, macho_file: *MachO) u64 {
    const header = macho_file.sections.items(.header)[thunk.out_n_sect];
    return header.addr + thunk.value;
}

pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
    return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size;
}

pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
    const Instruction = aarch64.encoding.Instruction;
    for (thunk.symbols.keys(), 0..) |ref, i| {
        const sym = ref.getSymbol(macho_file).?;
        const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
        const taddr = sym.getAddress(.{}, macho_file);
        const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
        try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
        try writer.writeInt(u32, @bitCast(
            Instruction.add(.x16, .x16, .{ .immediate = @truncate(taddr) }),
        ), .little);
        try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
    }
}

pub fn calcSymtabSize(thunk: *Thunk, macho_file: *MachO) void {
    thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
    for (thunk.symbols.keys()) |ref| {
        const sym = ref.getSymbol(macho_file).?;
        thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + "__thunk".len + 1));
    }
}

pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void {
    var n_strx = thunk.output_symtab_ctx.stroff;
    for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
        const sym = ref.getSymbol(macho_file).?;
        const name = sym.getName(macho_file);
        const out_sym = &ctx.symtab.items[ilocal];
        out_sym.n_strx = n_strx;
        @memcpy(ctx.strtab.items[n_strx..][0..name.len], name);
        n_strx += @intCast(name.len);
        @memcpy(ctx.strtab.items[n_strx..][0.."__thunk".len], "__thunk");
        n_strx += @intCast("__thunk".len);
        ctx.strtab.items[n_strx] = 0;
        n_strx += 1;
        out_sym.n_type = .{ .bits = .{ .ext = false, .type = .sect, .pext = false, .is_stab = 0 } };
        out_sym.n_sect = @intCast(thunk.out_n_sect + 1);
        out_sym.n_value = @intCast(thunk.getTargetAddress(ref, macho_file));
        out_sym.n_desc = @bitCast(@as(u16, 0));
    }
}

pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Alt(Format, Format.default) {
    return .{ .data = .{
        .thunk = thunk,
        .macho_file = macho_file,
    } };
}

const Format = struct {
    thunk: Thunk,
    macho_file: *MachO,

    fn default(f: Format, w: *Writer) Writer.Error!void {
        const thunk = f.thunk;
        const macho_file = f.macho_file;
        try w.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() });
        for (thunk.symbols.keys()) |ref| {
            const sym = ref.getSymbol(macho_file).?;
            try w.print("  {f} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value });
        }
    }
};

const trampoline_size = 3 * @sizeOf(u32);

pub const Index = u32;

const aarch64 = @import("../aarch64.zig");
const assert = std.debug.assert;
const log = std.log.scoped(.link);
const macho = std.macho;
const math = std.math;
const mem = std.mem;
const std = @import("std");
const trace = @import("../../tracy.zig").trace;
const Writer = std.Io.Writer;

const Allocator = mem.Allocator;
const Atom = @import("Atom.zig");
const MachO = @import("../MachO.zig");
const Relocation = @import("Relocation.zig");
const Symbol = @import("Symbol.zig");

const Thunk = @This();