1value: i64 = 0,
2output_section_index: u32 = 0,
3symbols: std.array_hash_map.Auto(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 dev.checkAny(&.{ .llvm_backend, .aarch64_backend });
95 for (thunk.symbols.keys(), 0..) |ref, i| {
96 const sym = elf_file.symbol(ref).?;
97 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
98 const taddr = sym.address(.{}, elf_file);
99 try writer.writeInt(u32, @bitCast(
100 util.encoding.Instruction.adrp(.x16, try util.calcNumberOfPages(saddr, taddr) << 12),
101 ), .little);
102 try writer.writeInt(u32, @bitCast(util.encoding.Instruction.add(
103 .x16,
104 .x16,
105 .{ .immediate = @truncate(@as(u64, @bitCast(taddr))) },
106 )), .little);
107 try writer.writeInt(u32, @bitCast(util.encoding.Instruction.br(.x16)), .little);
108 }
109 }
110
111 const trampoline_size = 3 * @sizeOf(u32);
112
113 const util = @import("../aarch64.zig");
114};
115
116const assert = std.debug.assert;
117const dev = @import("../../dev.zig");
118const elf = std.elf;
119const log = std.log.scoped(.link);
120const math = std.math;
121const mem = std.mem;
122const std = @import("std");
123
124const Allocator = mem.Allocator;
125const Atom = @import("Atom.zig");
126const Elf = @import("../Elf.zig");
127const Symbol = @import("Symbol.zig");
128
129const Thunk = @This();