master
  1value: i64 = 0,
  2output_section_index: u32 = 0,
  3symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .empty,
  4output_symtab_ctx: Elf.SymtabCtx = .{},
  5
  6pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
  7    thunk.symbols.deinit(allocator);
  8}
  9
 10pub fn size(thunk: Thunk, elf_file: *Elf) usize {
 11    const cpu_arch = elf_file.getTarget().cpu.arch;
 12    return thunk.symbols.keys().len * trampolineSize(cpu_arch);
 13}
 14
 15pub fn address(thunk: Thunk, elf_file: *Elf) i64 {
 16    const shdr = elf_file.sections.items(.shdr)[thunk.output_section_index];
 17    return @as(i64, @intCast(shdr.sh_addr)) + thunk.value;
 18}
 19
 20pub fn targetAddress(thunk: Thunk, ref: Elf.Ref, elf_file: *Elf) i64 {
 21    const cpu_arch = elf_file.getTarget().cpu.arch;
 22    return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(ref).? * trampolineSize(cpu_arch)));
 23}
 24
 25pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
 26    switch (elf_file.getTarget().cpu.arch) {
 27        .aarch64, .aarch64_be => try aarch64.write(thunk, elf_file, writer),
 28        .x86_64, .riscv64, .riscv64be => unreachable,
 29        else => @panic("unhandled arch"),
 30    }
 31}
 32
 33pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void {
 34    thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
 35    for (thunk.symbols.keys()) |ref| {
 36        const sym = elf_file.symbol(ref).?;
 37        thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1));
 38    }
 39}
 40
 41pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void {
 42    const cpu_arch = elf_file.getTarget().cpu.arch;
 43    for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
 44        const sym = elf_file.symbol(ref).?;
 45        const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
 46        elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
 47        elf_file.strtab.appendSliceAssumeCapacity("$thunk");
 48        elf_file.strtab.appendAssumeCapacity(0);
 49        elf_file.symtab.items[ilocal] = .{
 50            .st_name = st_name,
 51            .st_info = elf.STT_FUNC,
 52            .st_other = 0,
 53            .st_shndx = @intCast(thunk.output_section_index),
 54            .st_value = @intCast(thunk.targetAddress(ref, elf_file)),
 55            .st_size = trampolineSize(cpu_arch),
 56        };
 57    }
 58}
 59
 60fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) usize {
 61    return switch (cpu_arch) {
 62        .aarch64, .aarch64_be => aarch64.trampoline_size,
 63        .x86_64, .riscv64, .riscv64be => unreachable,
 64        else => @panic("unhandled arch"),
 65    };
 66}
 67
 68pub fn fmt(thunk: Thunk, elf_file: *Elf) std.fmt.Alt(Format, Format.default) {
 69    return .{ .data = .{
 70        .thunk = thunk,
 71        .elf_file = elf_file,
 72    } };
 73}
 74
 75const Format = struct {
 76    thunk: Thunk,
 77    elf_file: *Elf,
 78
 79    fn default(f: Format, writer: *std.Io.Writer) std.Io.Writer.Error!void {
 80        const thunk = f.thunk;
 81        const elf_file = f.elf_file;
 82        try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) });
 83        for (thunk.symbols.keys()) |ref| {
 84            const sym = elf_file.symbol(ref).?;
 85            try writer.print("  {f} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value });
 86        }
 87    }
 88};
 89
 90pub const Index = u32;
 91
 92const aarch64 = struct {
 93    fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
 94        for (thunk.symbols.keys(), 0..) |ref, i| {
 95            const sym = elf_file.symbol(ref).?;
 96            const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
 97            const taddr = sym.address(.{}, elf_file);
 98            try writer.writeInt(u32, @bitCast(
 99                util.encoding.Instruction.adrp(.x16, try util.calcNumberOfPages(saddr, taddr) << 12),
100            ), .little);
101            try writer.writeInt(u32, @bitCast(util.encoding.Instruction.add(
102                .x16,
103                .x16,
104                .{ .immediate = @truncate(@as(u64, @bitCast(taddr))) },
105            )), .little);
106            try writer.writeInt(u32, @bitCast(util.encoding.Instruction.br(.x16)), .little);
107        }
108    }
109
110    const trampoline_size = 3 * @sizeOf(u32);
111
112    const util = @import("../aarch64.zig");
113};
114
115const assert = std.debug.assert;
116const elf = std.elf;
117const log = std.log.scoped(.link);
118const math = std.math;
119const mem = std.mem;
120const std = @import("std");
121
122const Allocator = mem.Allocator;
123const Atom = @import("Atom.zig");
124const Elf = @import("../Elf.zig");
125const Symbol = @import("Symbol.zig");
126
127const Thunk = @This();