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 };