master
1pub const Kind = enum {
2 none,
3 other,
4 abs,
5 copy,
6 rel,
7 irel,
8 glob_dat,
9 jump_slot,
10 dtpmod,
11 dtpoff,
12 tpoff,
13 tlsdesc,
14};
15
16fn Table(comptime len: comptime_int, comptime RelType: type, comptime mapping: [len]struct { Kind, RelType }) type {
17 return struct {
18 fn decode(r_type: u32) Kind {
19 inline for (mapping) |entry| {
20 if (@intFromEnum(entry[1]) == r_type) return entry[0];
21 }
22 return .other;
23 }
24
25 fn encode(comptime kind: Kind) u32 {
26 inline for (mapping) |entry| {
27 if (entry[0] == kind) return @intFromEnum(entry[1]);
28 }
29 @panic("encoding .other is ambiguous");
30 }
31 };
32}
33
34const x86_64_relocs = Table(11, elf.R_X86_64, .{
35 .{ .none, .NONE },
36 .{ .abs, .@"64" },
37 .{ .copy, .COPY },
38 .{ .rel, .RELATIVE },
39 .{ .irel, .IRELATIVE },
40 .{ .glob_dat, .GLOB_DAT },
41 .{ .jump_slot, .JUMP_SLOT },
42 .{ .dtpmod, .DTPMOD64 },
43 .{ .dtpoff, .DTPOFF64 },
44 .{ .tpoff, .TPOFF64 },
45 .{ .tlsdesc, .TLSDESC },
46});
47
48const aarch64_relocs = Table(11, elf.R_AARCH64, .{
49 .{ .none, .NONE },
50 .{ .abs, .ABS64 },
51 .{ .copy, .COPY },
52 .{ .rel, .RELATIVE },
53 .{ .irel, .IRELATIVE },
54 .{ .glob_dat, .GLOB_DAT },
55 .{ .jump_slot, .JUMP_SLOT },
56 .{ .dtpmod, .TLS_DTPMOD },
57 .{ .dtpoff, .TLS_DTPREL },
58 .{ .tpoff, .TLS_TPREL },
59 .{ .tlsdesc, .TLSDESC },
60});
61
62const riscv64_relocs = Table(11, elf.R_RISCV, .{
63 .{ .none, .NONE },
64 .{ .abs, .@"64" },
65 .{ .copy, .COPY },
66 .{ .rel, .RELATIVE },
67 .{ .irel, .IRELATIVE },
68 .{ .glob_dat, .@"64" },
69 .{ .jump_slot, .JUMP_SLOT },
70 .{ .dtpmod, .TLS_DTPMOD64 },
71 .{ .dtpoff, .TLS_DTPREL64 },
72 .{ .tpoff, .TLS_TPREL64 },
73 .{ .tlsdesc, .TLSDESC },
74});
75
76pub fn decode(r_type: u32, cpu_arch: std.Target.Cpu.Arch) ?Kind {
77 return switch (cpu_arch) {
78 .x86_64 => x86_64_relocs.decode(r_type),
79 .aarch64, .aarch64_be => aarch64_relocs.decode(r_type),
80 .riscv64, .riscv64be => riscv64_relocs.decode(r_type),
81 else => @panic("TODO unhandled cpu arch"),
82 };
83}
84
85pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 {
86 return switch (cpu_arch) {
87 .x86_64 => x86_64_relocs.encode(kind),
88 .aarch64, .aarch64_be => aarch64_relocs.encode(kind),
89 .riscv64, .riscv64be => riscv64_relocs.encode(kind),
90 else => @panic("TODO unhandled cpu arch"),
91 };
92}
93
94pub const dwarf = struct {
95 pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 {
96 return switch (cpu_arch) {
97 .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (format) {
98 .@"32" => .@"32",
99 .@"64" => .@"64",
100 })),
101 .aarch64, .aarch64_be => @intFromEnum(@as(elf.R_AARCH64, switch (format) {
102 .@"32" => .ABS32,
103 .@"64" => .ABS64,
104 })),
105 .riscv64, .riscv64be => @intFromEnum(@as(elf.R_RISCV, switch (format) {
106 .@"32" => .@"32",
107 .@"64" => .@"64",
108 })),
109 else => @panic("TODO unhandled cpu arch"),
110 };
111 }
112
113 pub fn externalRelocType(
114 target: Symbol,
115 source_section: Dwarf.Section.Index,
116 address_size: Dwarf.AddressSize,
117 cpu_arch: std.Target.Cpu.Arch,
118 ) u32 {
119 return switch (cpu_arch) {
120 .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (source_section) {
121 else => switch (address_size) {
122 .@"32" => if (target.flags.is_tls) .DTPOFF32 else .@"32",
123 .@"64" => if (target.flags.is_tls) .DTPOFF64 else .@"64",
124 else => unreachable,
125 },
126 .debug_frame => .PC32,
127 })),
128 .aarch64, .aarch64_be => @intFromEnum(@as(elf.R_AARCH64, switch (source_section) {
129 else => switch (address_size) {
130 .@"32" => .ABS32,
131 .@"64" => .ABS64,
132 else => unreachable,
133 },
134 .debug_frame => .PREL32,
135 })),
136 .riscv64, .riscv64be => @intFromEnum(@as(elf.R_RISCV, switch (source_section) {
137 else => switch (address_size) {
138 .@"32" => .@"32",
139 .@"64" => .@"64",
140 else => unreachable,
141 },
142 .debug_frame => unreachable,
143 })),
144 else => @panic("TODO unhandled cpu arch"),
145 };
146 }
147
148 const DW = std.dwarf;
149};
150
151const FormatRelocTypeCtx = struct {
152 r_type: u32,
153 cpu_arch: std.Target.Cpu.Arch,
154};
155
156pub fn fmtRelocType(r_type: u32, cpu_arch: std.Target.Cpu.Arch) std.fmt.Alt(FormatRelocTypeCtx, formatRelocType) {
157 return .{ .data = .{
158 .r_type = r_type,
159 .cpu_arch = cpu_arch,
160 } };
161}
162
163fn formatRelocType(ctx: FormatRelocTypeCtx, writer: *std.Io.Writer) std.Io.Writer.Error!void {
164 const r_type = ctx.r_type;
165 switch (ctx.cpu_arch) {
166 .x86_64 => try writer.print("R_X86_64_{s}", .{@tagName(@as(elf.R_X86_64, @enumFromInt(r_type)))}),
167 .aarch64, .aarch64_be => try writer.print("R_AARCH64_{s}", .{@tagName(@as(elf.R_AARCH64, @enumFromInt(r_type)))}),
168 .riscv64, .riscv64be => try writer.print("R_RISCV_{s}", .{@tagName(@as(elf.R_RISCV, @enumFromInt(r_type)))}),
169 else => unreachable,
170 }
171}
172
173const assert = std.debug.assert;
174const elf = std.elf;
175const std = @import("std");
176
177const Dwarf = @import("../Dwarf.zig");
178const Elf = @import("../Elf.zig");
179const Symbol = @import("Symbol.zig");