lib/tldr/src/formats/elf/ehframe/header/reservation.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const root = @import("../../../../root.zig");
 3 const elf = @import("../../root.zig");
 4 const ehframe = @import("../root.zig");
 5 
 6 const model = root.model;
 7 const format = elf.format;
 8 const layout = elf.layout;
 9 const output_section = elf.output_section;
10 const parser = elf.parser;
11 const ObjectFile = parser.ObjectFile;
12 const ObjectLayout = layout.ObjectLayout;
13 const OutputSection = layout.OutputSection;
14 const Rela = format.Rela;
15 const OutputSectionKind = output_section.OutputSectionKind;
16 const output_section_count = output_section.output_section_count;
17 const eh_frame_hdr_fixed_size = format.eh_frame_hdr_fixed_size;
18 const eh_frame_hdr_entry_size = format.eh_frame_hdr_entry_size;
19 const contributionAt = layout.contributionAt;
20 const ehFrameSectionLayout = layout.ehFrameSection;
21 const sectionBytes = format.sectionBytes;
22 const readU32 = format.readU32;
23 const record = ehframe.record;
24 const section = ehframe.section;
25 
26 pub fn reserve(
27     output_sections: *[output_section_count]OutputSection,
28     objects: []const ObjectFile,
29     layouts: []const ObjectLayout,
30     options: model.LinkOptions,
31 ) model.Error!void {
32     if (!options.eh_frame_header) return;
33     const count = try countEntries(objects, layouts);
34     if (count == 0) return;
35     const header_size = try size(count);
36     var output = &output_sections[@backingInt(OutputSectionKind.eh_frame_hdr)];
37     output.file_size = header_size;
38     output.memory_size = header_size;
39     output.alignment = @max(output.alignment, 4);
40 }
41 
42 pub fn size(entry_count: usize) model.Error!u64 {
43     const count = std.math.cast(u64, entry_count) orelse return error.InvalidRange;
44     if (count > (std.math.maxInt(u64) - eh_frame_hdr_fixed_size) / eh_frame_hdr_entry_size) return error.InvalidRange;
45     return eh_frame_hdr_fixed_size + count * eh_frame_hdr_entry_size;
46 }
47 
48 fn countEntries(
49     objects: []const ObjectFile,
50     layouts: []const ObjectLayout,
51 ) model.Error!usize {
52     var count: usize = 0;
53     for (objects, 0..) |object, object_index| {
54         const object_layout = layouts[object_index];
55         for (object.sections, 0..) |input_section, section_index| {
56             if (contributionAt(object_layout.sections, section_index) == null) continue;
57             if (!section.is(object, section_index, input_section)) continue;
58             const bytes = try sectionBytes(object.bytes, input_section);
59             if (ehFrameSectionLayout(object_layout, section_index)) |eh_frame_section| {
60                 var cursor = record.Cursor.init(eh_frame_section.relocations);
61                 for (eh_frame_section.pieces) |piece| {
62                     if (try record.hasHeaderEntry(bytes, piece.input_offset, piece.size, piece.output_offset, &cursor)) count += 1;
63                 }
64                 continue;
65             }
66             try countRawEntries(bytes, object.relocationsForSection(section_index), &count);
67         }
68     }
69     return count;
70 }
71 
72 fn countRawEntries(
73     bytes: []const u8,
74     relocations: []const Rela,
75     count: *usize,
76 ) model.Error!void {
77     var cursor = record.Cursor.init(relocations);
78     var input_offset: u64 = 0;
79     while (input_offset < bytes.len) {
80         const record_start: usize = @intCast(input_offset);
81         if (bytes.len - record_start < 4) return error.InvalidObject;
82         const record_length = readU32(bytes, record_start);
83         if (record_length == 0xffffffff) return error.UnsupportedFormat;
84         const record_size = @as(u64, record_length) + 4;
85         if (record_size < 4) return error.InvalidObject;
86         if (input_offset > std.math.maxInt(u64) - record_size) return error.InvalidObject;
87         const record_end = input_offset + record_size;
88         if (record_end > bytes.len) return error.InvalidObject;
89         if (try record.hasHeaderEntry(bytes, input_offset, record_size, input_offset, &cursor)) count.* += 1;
90         if (record_length == 0) break;
91         input_offset = record_end;
92     }
93 }