lib/tldr/src/formats/elf/archive/object.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const root = @import("../../../root.zig");
3 const elf = @import("../root.zig");
4 const definition = @import("definition.zig");
5
6 const Allocator = std.mem.Allocator;
7 const model = root.model;
8 const ObjectFile = elf.parser.ObjectFile;
9 const Symbol = elf.format.Symbol;
10 const globalSymbolCanBeAdded = elf.symbol_table.globalSymbolCanBeAdded;
11
12 pub fn record(
13 allocator: Allocator,
14 objects: []const ObjectFile,
15 object_index: usize,
16 definitions: *definition.Index,
17 unresolved_names: *usize,
18 active_candidate_counts: []usize,
19 pending: *definition.Queue,
20 ) model.Error!void {
21 const parsed_object = objects[object_index];
22 for (parsed_object.symbols) |symbol| {
23 try recordSymbol(
24 allocator,
25 symbol,
26 globalSymbolCanBeAdded(parsed_object, symbol),
27 definitions,
28 unresolved_names,
29 active_candidate_counts,
30 pending,
31 );
32 }
33 }
34
35 pub fn recordSymbols(
36 allocator: Allocator,
37 symbols: []const Symbol,
38 definitions: *definition.Index,
39 unresolved_names: *usize,
40 active_candidate_counts: []usize,
41 pending: *definition.Queue,
42 ) model.Error!void {
43 for (symbols) |symbol| {
44 try recordSymbol(
45 allocator,
46 symbol,
47 symbol.isGlobalDefinition(),
48 definitions,
49 unresolved_names,
50 active_candidate_counts,
51 pending,
52 );
53 }
54 }
55
56 fn recordSymbol(
57 allocator: Allocator,
58 symbol: Symbol,
59 records_definition: bool,
60 definitions: *definition.Index,
61 unresolved_names: *usize,
62 active_candidate_counts: []usize,
63 pending: *definition.Queue,
64 ) model.Error!void {
65 if (records_definition) {
66 return definition.define(allocator, definitions, unresolved_names, active_candidate_counts, symbol.name);
67 }
68 if (!symbol.isUndefined()) return;
69 if (symbol.name.len == 0) return;
70 if (symbol.binding() != std.elf.STB_GLOBAL) return;
71 try definition.require(allocator, definitions, unresolved_names, active_candidate_counts, pending, symbol.name);
72 }
73
74 fn testSymbol(name: []const u8, section_index: u16, symbol_binding: u8) Symbol {
75 return .{
76 .name_offset = 0,
77 .info = symbol_binding << 4,
78 .other = 0,
79 .section_index = section_index,
80 .value = 0,
81 .size = 0,
82 .name = name,
83 };
84 }
85
86 test "recording symbols resolves required names through definitions" {
87 const allocator = std.testing.allocator;
88 var definitions: definition.Index = .{};
89 defer definition.deinit(allocator, &definitions);
90 var counts = [_]usize{0};
91 var pending = definition.Queue.initContext({});
92 defer pending.deinit(allocator);
93 var unresolved_names: usize = 0;
94
95 try definition.add(allocator, &definitions, "puts", 0, &counts, &pending);
96
97 const undefined_global = testSymbol("puts", std.elf.SHN_UNDEF, std.elf.STB_GLOBAL);
98 const undefined_weak = testSymbol("vfork", std.elf.SHN_UNDEF, std.elf.STB_WEAK);
99 const undefined_local = testSymbol("tls", std.elf.SHN_UNDEF, std.elf.STB_LOCAL);
100 try recordSymbols(
101 allocator,
102 &.{ undefined_global, undefined_weak, undefined_local },
103 &definitions,
104 &unresolved_names,
105 &counts,
106 &pending,
107 );
108 try std.testing.expectEqual(@as(usize, 1), unresolved_names);
109 try std.testing.expectEqual(@as(usize, 1), counts[0]);
110 try std.testing.expectEqual(@as(?usize, 0), pending.peek());
111
112 const defining_global = testSymbol("puts", 1, std.elf.STB_GLOBAL);
113 try recordSymbols(allocator, &.{defining_global}, &definitions, &unresolved_names, &counts, &pending);
114 try std.testing.expectEqual(@as(usize, 0), unresolved_names);
115 try std.testing.expectEqual(@as(usize, 0), counts[0]);
116
117 try recordSymbols(allocator, &.{undefined_global}, &definitions, &unresolved_names, &counts, &pending);
118 try std.testing.expectEqual(@as(usize, 0), unresolved_names);
119 try std.testing.expectEqual(@as(usize, 0), counts[0]);
120 }