lib/tldr/src/formats/elf/group/discard.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const root = @import("../../../root.zig");
3 const elf = @import("../root.zig");
4 const record = @import("record.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 SymbolRef = elf.layout.SymbolRef;
11 const ensureDiscardedSections = elf.section_state.ensureDiscardedSections;
12 const sectionName = elf.parser.sectionName;
13
14 pub fn duplicates(
15 allocator: Allocator,
16 objects: []ObjectFile,
17 ) model.Error!void {
18 var retained: std.StringHashMapUnmanaged(SymbolRef) = .{};
19 defer retained.deinit(allocator);
20
21 for (objects, 0..) |*object, object_index| {
22 if (!object.has_group_sections) continue;
23 for (object.sections) |section| {
24 if (section.section_type != std.elf.SHT_GROUP) continue;
25 if (section.info >= object.symbols.len) return error.InvalidObject;
26
27 const group_bytes = try record.bytes(object.*, section);
28 if (group_bytes.len == 0) return error.InvalidObject;
29 if ((record.word(group_bytes, 0) & std.elf.GRP_COMDAT) == 0) continue;
30
31 const signature = object.symbols[section.info];
32 const name = try signatureName(object.*, signature);
33 const gop = try retained.getOrPut(allocator, name);
34 if (gop.found_existing) {
35 try discardMembers(allocator, object, group_bytes);
36 } else {
37 gop.value_ptr.* = .{
38 .object_index = object_index,
39 .symbol_index = section.info,
40 };
41 }
42 }
43 }
44 }
45
46 fn signatureName(object: ObjectFile, signature: Symbol) model.Error![]const u8 {
47 if (signature.name.len != 0) return signature.name;
48 if (!signature.isSection()) return error.InvalidObject;
49 if (signature.section_index == 0 or signature.section_index >= object.sections.len) return error.InvalidObject;
50 const name = try sectionName(object, signature.section_index);
51 if (name.len == 0) return error.InvalidObject;
52 return name;
53 }
54
55 fn discardMembers(allocator: Allocator, object: *ObjectFile, group_bytes: []const u8) model.Error!void {
56 const discarded_sections = try ensureDiscardedSections(allocator, object);
57 var member_iterator = record.members(group_bytes);
58 while (member_iterator.next()) |member_index| {
59 if (member_index >= object.sections.len) return error.MissingSection;
60 discarded_sections[member_index] = true;
61 }
62 }