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 }