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 }