lib/tldr/src/formats/elf/liveness/symbols.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const root = @import("../../../root.zig");
3 const elf = @import("../root.zig");
4 const state = @import("state.zig");
5
6 const model = root.model;
7 const GlobalSymbol = elf.layout.GlobalSymbol;
8 const ObjectFile = elf.parser.ObjectFile;
9 const SectionRef = elf.parser.SectionRef;
10 const State = state.State;
11 const SymbolRef = elf.layout.SymbolRef;
12 const SyntheticBoundary = elf.addressing.Boundary;
13 const boundarySectionNameMatches = elf.addressing.boundarySectionNameMatches;
14 const foldedSection = elf.section_state.foldedSection;
15 const sectionDiscarded = elf.section_state.sectionDiscarded;
16 const sectionIsAllocated = elf.format.sectionIsAllocated;
17 const sectionNameOrEmpty = elf.parser.sectionNameOrEmpty;
18 const symbolSectionDiscarded = elf.section_state.symbolSectionDiscarded;
19 const syntheticBoundaryForSymbol = elf.addressing.boundaryForSymbol;
20
21 pub fn mark(
22 objects: []const ObjectFile,
23 globals: *const std.StringHashMapUnmanaged(GlobalSymbol),
24 live: *State,
25 symbol_ref: SymbolRef,
26 options: model.LinkOptions,
27 ) model.Error!void {
28 if (symbol_ref.object_index >= objects.len) return error.InvalidObject;
29 const object = objects[symbol_ref.object_index];
30 if (symbol_ref.symbol_index >= object.symbols.len) return error.UndefinedSymbol;
31
32 const symbol = object.symbols[symbol_ref.symbol_index];
33 if (symbol.isUndefined()) {
34 const global = globals.get(symbol.name) orelse {
35 if (symbol.isWeakUndefined()) return;
36 const boundary = syntheticBoundaryForSymbol(symbol.name) orelse {
37 elf.diagnostic.recordUndefinedSymbol(options, object, symbol);
38 return error.UndefinedSymbol;
39 };
40 if (try markSyntheticBoundarySections(objects, live, boundary)) return;
41 if (boundary.optional) return;
42 elf.diagnostic.recordUndefinedSymbol(options, object, symbol);
43 return error.UndefinedSymbol;
44 };
45 return mark(objects, globals, live, global.ref, options);
46 }
47 if (symbolSectionDiscarded(object, symbol) and symbol.name.len != 0) {
48 const global = globals.get(symbol.name) orelse return error.MissingSection;
49 return mark(objects, globals, live, global.ref, options);
50 }
51 if (symbol.isCommon()) return;
52 if (symbol.isAbsolute()) return;
53 if (symbol.section_index >= object.sections.len) return error.UnsupportedRelocation;
54
55 try state.markSection(
56 live,
57 objects,
58 .{
59 .object_index = symbol_ref.object_index,
60 .section_index = symbol.section_index,
61 },
62 );
63 }
64
65 fn markSyntheticBoundarySections(
66 objects: []const ObjectFile,
67 live: *State,
68 boundary: SyntheticBoundary,
69 ) model.Error!bool {
70 var found = false;
71 for (objects, 0..) |object, object_index| {
72 for (object.sections, 0..) |section, section_index| {
73 if (!sectionIsAllocated(section)) continue;
74 if (section.size == 0) continue;
75 if (sectionDiscarded(object, section_index)) continue;
76 if (foldedSection(object, section_index) != null) continue;
77 if (!boundarySectionNameMatches(boundary, sectionNameOrEmpty(object, section_index))) continue;
78 try state.markSection(
79 live,
80 objects,
81 .{
82 .object_index = object_index,
83 .section_index = section_index,
84 },
85 );
86 found = true;
87 }
88 }
89 return found;
90 }
91
92 pub fn markRelocationTargets(
93 objects: []const ObjectFile,
94 globals: *const std.StringHashMapUnmanaged(GlobalSymbol),
95 live: *State,
96 section_ref: SectionRef,
97 options: model.LinkOptions,
98 ) model.Error!void {
99 const object = objects[section_ref.object_index];
100 for (object.relocationsForSection(section_ref.section_index)) |entry| {
101 if (elf.relocation.isNone(entry)) continue;
102 if (entry.symbolIndex() >= object.symbols.len) return error.UndefinedSymbol;
103 try mark(
104 objects,
105 globals,
106 live,
107 .{
108 .object_index = section_ref.object_index,
109 .symbol_index = @intCast(entry.symbolIndex()),
110 },
111 options,
112 );
113 }
114 }