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 }