lib/tldr/src/formats/elf/address/symbol.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const root = @import("../../../root.zig");
  3 const elf = @import("../root.zig");
  4 const boundary = @import("boundary.zig");
  5 const cache = @import("cache.zig");
  6 
  7 const model = root.model;
  8 const format = elf.format;
  9 const layout = elf.layout;
 10 const merge = elf.merge;
 11 const section_state = elf.section_state;
 12 
 13 const Access = cache.Access;
 14 const Cache = cache.Cache;
 15 const GlobalSymbol = layout.GlobalSymbol;
 16 const ObjectFile = elf.parser.ObjectFile;
 17 const ObjectLayout = layout.ObjectLayout;
 18 const OutputSection = layout.OutputSection;
 19 const Symbol = format.Symbol;
 20 const SymbolRef = layout.SymbolRef;
 21 const contributionAt = layout.contributionAt;
 22 const foldedSection = section_state.foldedSection;
 23 const symbolSectionDiscarded = section_state.symbolSectionDiscarded;
 24 
 25 pub fn address(
 26     comptime cache_access: Access,
 27     objects: []const ObjectFile,
 28     layouts: []const ObjectLayout,
 29     output_sections: []const OutputSection,
 30     globals: *const std.StringHashMapUnmanaged(GlobalSymbol),
 31     symbol_addresses: *Cache,
 32     object_index: usize,
 33     symbol_index: usize,
 34 ) model.Error!u64 {
 35     if (symbol_index >= objects[object_index].symbols.len) return error.UndefinedSymbol;
 36     const cached = symbol_addresses.slot(object_index, symbol_index);
 37     const cached_value = cache.load(cache_access, cached);
 38     if (cached_value != Cache.missing) return cached_value;
 39 
 40     const symbol_record = objects[object_index].symbols[symbol_index];
 41     if (symbol_record.isUndefined()) {
 42         const global = globals.get(symbol_record.name) orelse {
 43             if (boundary.forSymbol(symbol_record.name)) |symbol_boundary| {
 44                 if (symbol_addresses.syntheticBoundaryAddress(symbol_boundary)) |boundary_address| {
 45                     return cache.store(cache_access, cached, boundary_address);
 46                 }
 47             }
 48             if (symbol_record.isWeakUndefined()) {
 49                 return cache.store(cache_access, cached, 0);
 50             }
 51             return error.UndefinedSymbol;
 52         };
 53         const resolved = try address(
 54             cache_access,
 55             objects,
 56             layouts,
 57             output_sections,
 58             globals,
 59             symbol_addresses,
 60             global.ref.object_index,
 61             global.ref.symbol_index,
 62         );
 63         return cache.store(cache_access, cached, resolved);
 64     }
 65     if (symbolSectionDiscarded(objects[object_index], symbol_record) and symbol_record.name.len != 0) {
 66         const global = globals.get(symbol_record.name) orelse return error.MissingSection;
 67         const current_ref = SymbolRef{ .object_index = object_index, .symbol_index = symbol_index };
 68         if (global.ref.eql(current_ref)) return error.MissingSection;
 69         const resolved = try address(
 70             cache_access,
 71             objects,
 72             layouts,
 73             output_sections,
 74             globals,
 75             symbol_addresses,
 76             global.ref.object_index,
 77             global.ref.symbol_index,
 78         );
 79         return cache.store(cache_access, cached, resolved);
 80     }
 81     if (symbol_record.isCommon() and symbol_record.name.len != 0) {
 82         const global = globals.get(symbol_record.name) orelse return error.UndefinedSymbol;
 83         const current_ref = SymbolRef{ .object_index = object_index, .symbol_index = symbol_index };
 84         if (!global.ref.eql(current_ref)) {
 85             const resolved = try address(cache_access, objects, layouts, output_sections, globals, symbol_addresses, global.ref.object_index, global.ref.symbol_index);
 86             return cache.store(cache_access, cached, resolved);
 87         }
 88     }
 89     if (symbol_record.isAbsolute()) return cache.store(cache_access, cached, symbol_record.value);
 90     if (symbol_record.isCommon()) {
 91         const object_layout = layouts[object_index];
 92         if (symbol_index >= object_layout.common_symbols.len) return error.UnsupportedRelocation;
 93         const common_contribution = contributionAt(object_layout.common_symbols, symbol_index) orelse return error.MissingSection;
 94         const output = output_sections[common_contribution.outputIndex()];
 95         return cache.store(cache_access, cached, output.address + common_contribution.offset);
 96     }
 97     return sectionAddress(cache_access, objects, layouts, output_sections, cached, object_index, symbol_record);
 98 }
 99 
100 pub fn relocation(
101     comptime cache_access: Access,
102     objects: []const ObjectFile,
103     layouts: []const ObjectLayout,
104     output_sections: []const OutputSection,
105     globals: *const std.StringHashMapUnmanaged(GlobalSymbol),
106     symbol_addresses: *Cache,
107     object_index: usize,
108     symbol_index: usize,
109 ) model.Error!i128 {
110     if (symbol_index >= objects[object_index].symbols.len) return error.UndefinedSymbol;
111 
112     const symbol_record = objects[object_index].symbols[symbol_index];
113     if (symbol_record.isUndefined()) {
114         const global = globals.get(symbol_record.name) orelse {
115             if (boundary.forSymbol(symbol_record.name)) |symbol_boundary| {
116                 if (symbol_addresses.syntheticBoundaryAddress(symbol_boundary)) |boundary_address| {
117                     return @intCast(boundary_address);
118                 }
119             }
120             if (symbol_record.isWeakUndefined()) return 0;
121             return error.UndefinedSymbol;
122         };
123         return relocation(
124             cache_access,
125             objects,
126             layouts,
127             output_sections,
128             globals,
129             symbol_addresses,
130             global.ref.object_index,
131             global.ref.symbol_index,
132         );
133     }
134     if (symbolSectionDiscarded(objects[object_index], symbol_record) and symbol_record.name.len != 0) {
135         const global = globals.get(symbol_record.name) orelse return error.MissingSection;
136         const current_ref = SymbolRef{ .object_index = object_index, .symbol_index = symbol_index };
137         if (global.ref.eql(current_ref)) return error.MissingSection;
138         return relocation(
139             cache_access,
140             objects,
141             layouts,
142             output_sections,
143             globals,
144             symbol_addresses,
145             global.ref.object_index,
146             global.ref.symbol_index,
147         );
148     }
149     if (symbol_record.isCommon() and symbol_record.name.len != 0) {
150         const global = globals.get(symbol_record.name) orelse return error.UndefinedSymbol;
151         const current_ref = SymbolRef{ .object_index = object_index, .symbol_index = symbol_index };
152         if (!global.ref.eql(current_ref)) {
153             return relocation(cache_access, objects, layouts, output_sections, globals, symbol_addresses, global.ref.object_index, global.ref.symbol_index);
154         }
155     }
156     if (symbol_record.isAbsolute()) return signedAbsoluteValue(symbol_record.value);
157     if (symbol_record.isCommon()) return @intCast(try address(cache_access, objects, layouts, output_sections, globals, symbol_addresses, object_index, symbol_index));
158     return @intCast(try sectionSymbolAddress(cache_access, objects, layouts, output_sections, symbol_addresses, object_index, symbol_index, symbol_record));
159 }
160 
161 pub fn isUnresolvedWeak(
162     object: ObjectFile,
163     symbol_index: usize,
164     globals: *const std.StringHashMapUnmanaged(GlobalSymbol),
165 ) bool {
166     if (symbol_index >= object.symbols.len) return false;
167     const symbol_record = object.symbols[symbol_index];
168     return symbol_record.isWeakUndefined() and !globals.contains(symbol_record.name);
169 }
170 
171 pub fn sectionSymbolAddress(
172     comptime cache_access: Access,
173     objects: []const ObjectFile,
174     layouts: []const ObjectLayout,
175     output_sections: []const OutputSection,
176     symbol_addresses: *Cache,
177     object_index: usize,
178     symbol_index: usize,
179     symbol_record: Symbol,
180 ) model.Error!u64 {
181     const cached = symbol_addresses.slot(object_index, symbol_index);
182     const cached_value = cache.load(cache_access, cached);
183     if (cached_value != Cache.missing) return cached_value;
184     return sectionAddress(cache_access, objects, layouts, output_sections, cached, object_index, symbol_record);
185 }
186 
187 fn sectionAddress(
188     comptime cache_access: Access,
189     objects: []const ObjectFile,
190     layouts: []const ObjectLayout,
191     output_sections: []const OutputSection,
192     cached: *u64,
193     object_index: usize,
194     symbol_record: Symbol,
195 ) model.Error!u64 {
196     const object = objects[object_index];
197     const object_layout = layouts[object_index];
198     if (symbol_record.section_index >= object.sections.len) return error.UnsupportedRelocation;
199     if (merge.piece(object_layout, object, symbol_record.section_index, symbol_record.value)) |entry| {
200         const output = output_sections[entry.contribution.outputIndex()];
201         const resolved = output.address + entry.contribution.offset + entry.intra_offset;
202         return cache.store(cache_access, cached, resolved);
203     }
204     const symbol_contribution = if (foldedSection(object, symbol_record.section_index)) |canonical|
205         (contributionAt(layouts[canonical.object_index].sections, canonical.section_index) orelse return error.MissingSection).*
206     else
207         (contributionAt(object_layout.sections, symbol_record.section_index) orelse return error.MissingSection).*;
208     const output = output_sections[symbol_contribution.outputIndex()];
209     const resolved = output.address + symbol_contribution.offset + symbol_record.value;
210     return cache.store(cache_access, cached, resolved);
211 }
212 
213 fn signedAbsoluteValue(value: u64) i128 {
214     return @as(i64, @bitCast(value));
215 }