lib/tldr/src/formats/elf/icf/fold.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const root = @import("../../../root.zig");
 3 const elf = @import("../root.zig");
 4 const hash = @import("hash.zig");
 5 const match = @import("match.zig");
 6 
 7 const Allocator = std.mem.Allocator;
 8 const model = root.model;
 9 const ObjectFile = elf.parser.ObjectFile;
10 const SectionRef = elf.parser.SectionRef;
11 const ensureFoldedSections = elf.section_state.ensureFoldedSections;
12 const foldedSection = elf.section_state.foldedSection;
13 const sectionDiscarded = elf.section_state.sectionDiscarded;
14 
15 const ClassMap = std.AutoHashMapUnmanaged(u64, std.ArrayListUnmanaged(SectionRef));
16 
17 pub fn fold(
18     allocator: Allocator,
19     objects: []ObjectFile,
20 ) model.Error!void {
21     var classes: ClassMap = .{};
22     defer {
23         var values = classes.valueIterator();
24         while (values.next()) |sections| sections.deinit(allocator);
25         classes.deinit(allocator);
26     }
27 
28     for (objects, 0..) |*object, object_index| {
29         const folded_sections = try ensureFoldedSections(allocator, object);
30         for (object.sections, 0..) |_, section_index| {
31             if (!sectionEligible(object.*, section_index)) continue;
32 
33             const section_hash = try hash.section(object.*, section_index);
34             const gop = try classes.getOrPut(allocator, section_hash);
35             if (!gop.found_existing) gop.value_ptr.* = .empty;
36 
37             var folded = false;
38             for (gop.value_ptr.items) |candidate_ref| {
39                 const candidate = objects[candidate_ref.object_index];
40                 if (try match.sections(object.*, section_index, candidate, candidate_ref.section_index)) {
41                     folded_sections[section_index] = candidate_ref;
42                     folded = true;
43                     break;
44                 }
45             }
46             if (!folded) {
47                 try gop.value_ptr.append(allocator, .{
48                     .object_index = object_index,
49                     .section_index = section_index,
50                 });
51             }
52         }
53     }
54 }
55 
56 fn sectionEligible(object: ObjectFile, section_index: usize) bool {
57     if (sectionDiscarded(object, section_index)) return false;
58     if (foldedSection(object, section_index) != null) return false;
59     const input_section = object.sections[section_index];
60     if (input_section.size == 0) return false;
61     if (input_section.section_type != std.elf.SHT_PROGBITS) return false;
62     if ((input_section.flags & std.elf.SHF_ALLOC) == 0) return false;
63     if ((input_section.flags & std.elf.SHF_EXECINSTR) == 0) return false;
64     if ((input_section.flags & std.elf.SHF_WRITE) != 0) return false;
65     return true;
66 }