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 }