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");