lib/tldr/src/formats/elf/relocation/target.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const root = @import("../../../root.zig");
3 const elf = @import("../root.zig");
4
5 const model = root.model;
6 const addressing = elf.addressing;
7 const ObjectFile = elf.parser.ObjectFile;
8 const ObjectLayout = elf.layout.ObjectLayout;
9 const OutputSection = elf.layout.OutputSection;
10 const GlobalSymbol = elf.layout.GlobalSymbol;
11 const Rela = elf.format.Rela;
12 const SymbolAddressCache = addressing.Cache;
13 const SymbolCacheAccess = addressing.Access;
14 const RelocationTarget = addressing.Target;
15 const relocationTargetAddress = addressing.relocationTarget;
16 const symbolTlsOffset = addressing.tlsOffset;
17
18 pub fn cached(
19 comptime cache_access: SymbolCacheAccess,
20 objects: []const ObjectFile,
21 layouts: []const ObjectLayout,
22 output_sections: []const OutputSection,
23 globals: *const std.StringHashMapUnmanaged(GlobalSymbol),
24 symbol_addresses: *SymbolAddressCache,
25 object_index: usize,
26 symbol_index: usize,
27 relocation: Rela,
28 needs_size: bool,
29 tls_offset: bool,
30 target_cache: *Cache,
31 ) model.Error!RelocationTarget {
32 const target = target_cache.get(object_index, symbol_index, relocation.addend, needs_size, tls_offset) orelse blk: {
33 const resolved = if (tls_offset)
34 RelocationTarget{
35 .address = @intCast(try symbolTlsOffset(objects, layouts, output_sections, globals, symbol_addresses, object_index, symbol_index)),
36 .addend = relocation.addend,
37 .size = 0,
38 }
39 else
40 try relocationTargetAddress(
41 cache_access,
42 objects,
43 layouts,
44 output_sections,
45 globals,
46 symbol_addresses,
47 object_index,
48 symbol_index,
49 relocation,
50 needs_size,
51 );
52 target_cache.put(object_index, symbol_index, relocation.addend, needs_size, tls_offset, resolved);
53 break :blk resolved;
54 };
55 return target;
56 }
57
58 pub fn cachedOrSkip(
59 comptime cache_access: SymbolCacheAccess,
60 objects: []const ObjectFile,
61 layouts: []const ObjectLayout,
62 output_sections: []const OutputSection,
63 globals: *const std.StringHashMapUnmanaged(GlobalSymbol),
64 symbol_addresses: *SymbolAddressCache,
65 object_index: usize,
66 symbol_index: usize,
67 relocation: Rela,
68 needs_size: bool,
69 tls_offset: bool,
70 ignore_missing_target: bool,
71 target_cache: *Cache,
72 ) model.Error!?RelocationTarget {
73 return cached(
74 cache_access,
75 objects,
76 layouts,
77 output_sections,
78 globals,
79 symbol_addresses,
80 object_index,
81 symbol_index,
82 relocation,
83 needs_size,
84 tls_offset,
85 target_cache,
86 ) catch |err| switch (err) {
87 error.MissingSection => if (ignore_missing_target) return null else return err,
88 else => return err,
89 };
90 }
91
92 pub const Cache = struct {
93 const entry_count = 64;
94 const invalid_object_index = std.math.maxInt(usize);
95
96 entries: [entry_count]Entry = @splat(Entry{}),
97
98 const Entry = struct {
99 object_index: usize = invalid_object_index,
100 symbol_index: usize = 0,
101 addend: i64 = 0,
102 needs_size: bool = false,
103 tls_offset: bool = false,
104 target: RelocationTarget = .{ .address = 0, .addend = 0, .size = 0 },
105 };
106
107 pub fn get(
108 self: *const Cache,
109 object_index: usize,
110 symbol_index: usize,
111 addend: i64,
112 needs_size: bool,
113 tls_offset: bool,
114 ) ?RelocationTarget {
115 const entry = self.entries[indexFor(object_index, symbol_index, addend, needs_size, tls_offset)];
116 if (entry.object_index != object_index) return null;
117 if (entry.symbol_index != symbol_index) return null;
118 if (entry.addend != addend) return null;
119 if (entry.needs_size != needs_size) return null;
120 if (entry.tls_offset != tls_offset) return null;
121 return entry.target;
122 }
123
124 pub fn put(
125 self: *Cache,
126 object_index: usize,
127 symbol_index: usize,
128 addend: i64,
129 needs_size: bool,
130 tls_offset: bool,
131 target: RelocationTarget,
132 ) void {
133 self.entries[indexFor(object_index, symbol_index, addend, needs_size, tls_offset)] = .{
134 .object_index = object_index,
135 .symbol_index = symbol_index,
136 .addend = addend,
137 .needs_size = needs_size,
138 .tls_offset = tls_offset,
139 .target = target,
140 };
141 }
142
143 fn indexFor(object_index: usize, symbol_index: usize, addend: i64, needs_size: bool, tls_offset: bool) usize {
144 const addend_bits: u64 = @bitCast(addend);
145 var hash = object_index *% 0x9e3779b1;
146 hash ^= symbol_index *% 0x85ebca6b;
147 hash ^= @as(usize, @truncate(addend_bits));
148 if (needs_size) hash ^= 0xc2b2ae35;
149 if (tls_offset) hash ^= 0x27d4eb2f;
150 return hash & (entry_count - 1);
151 }
152 };