lib/tldr/src/formats/elf/note.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const root = @import("../../root.zig");
3 const format = @import("format.zig");
4 const layout = @import("layout/root.zig");
5 const output_section = @import("section.zig");
6
7 const model = root.model;
8 const OutputSection = layout.OutputSection;
9 const OutputSectionKind = output_section.OutputSectionKind;
10 const SectionHeader = format.SectionHeader;
11 const output_section_count = output_section.output_section_count;
12 const requireRange = format.requireRange;
13 const writeU32 = format.writeU32;
14 const writeU64 = format.writeU64;
15
16 pub const section_name = ".note.gnu.build-id";
17 pub const desc_offset = format.build_id_note_desc_offset;
18 pub const fast_desc_size = format.build_id_fast_desc_size;
19 pub const sha1_desc_size = format.build_id_sha1_desc_size;
20
21 pub fn reserveBuildId(
22 output_sections: *[output_section_count]OutputSection,
23 options: model.LinkOptions,
24 ) void {
25 if (options.build_id == .none) return;
26 var output = &output_sections[@backingInt(OutputSectionKind.build_id_note)];
27 const note_size = size(options.build_id);
28 output.file_size = note_size;
29 output.memory_size = note_size;
30 output.alignment = @max(output.alignment, 4);
31 }
32
33 pub fn writeBuildIdHeader(image: []u8, offset: u64) model.Error!void {
34 try requireRange(image, offset, desc_offset);
35 const start: usize = @intCast(offset);
36 writeU32(image, start + 0, 4);
37 writeU32(image, start + 8, std.elf.NT_GNU_BUILD_ID);
38 image[start + 12] = 'G';
39 image[start + 13] = 'N';
40 image[start + 14] = 'U';
41 image[start + 15] = 0;
42 }
43
44 pub fn finishBuildId(
45 image: []u8,
46 output_sections: []const OutputSection,
47 options: model.LinkOptions,
48 ) model.Error!void {
49 if (options.build_id == .none) return;
50 const section = output_sections[@backingInt(OutputSectionKind.build_id_note)];
51 const note_size = size(options.build_id);
52 try requireRange(image, section.file_offset, note_size);
53 try finishBuildIdAt(image, section.file_offset, options.build_id);
54 }
55
56 pub fn finishBuildIdSection(
57 image: []u8,
58 section: SectionHeader,
59 mode: model.BuildIdMode,
60 ) model.Error!void {
61 if (mode == .none) return;
62 if (section.section_type != std.elf.SHT_NOTE) return error.InvalidElfHeader;
63 if (section.size != size(mode)) return error.InvalidElfHeader;
64 try requireRange(image, section.offset, section.size);
65 try finishBuildIdAt(image, section.offset, mode);
66 }
67
68 fn finishBuildIdAt(
69 image: []u8,
70 file_offset: u64,
71 mode: model.BuildIdMode,
72 ) model.Error!void {
73 const desc_size = descSize(mode);
74 const start: usize = @intCast(file_offset);
75 const desc_start = start + desc_offset;
76 writeU32(image, start + 4, @intCast(desc_size));
77 @memset(image[desc_start..][0..desc_size], 0);
78 switch (mode) {
79 .none => unreachable,
80 .fast => {
81 var hasher = std.hash.XxHash64.init(0);
82 hasher.update(image);
83 writeU64(image, desc_start, hasher.final());
84 },
85 .sha1 => {
86 var digest: [sha1_desc_size]u8 = undefined;
87 std.crypto.hash.Sha1.hash(image, &digest, .{});
88 @memcpy(image[desc_start..][0..sha1_desc_size], &digest);
89 },
90 }
91 }
92
93 pub fn patchGenerated(
94 image: []u8,
95 candidate_image: []const u8,
96 section: SectionHeader,
97 candidate_section: SectionHeader,
98 ) model.Error!void {
99 if (section.offset != candidate_section.offset) return error.InvalidElfHeader;
100 if (section.size != candidate_section.size) return error.InvalidElfHeader;
101 if (section.section_type != std.elf.SHT_NOTE or candidate_section.section_type != std.elf.SHT_NOTE) return error.InvalidElfHeader;
102 try requireRange(image, section.offset, section.size);
103 try requireRange(candidate_image, candidate_section.offset, candidate_section.size);
104 const start: usize = @intCast(section.offset);
105 const note_size: usize = @intCast(section.size);
106 @memcpy(image[start..][0..note_size], candidate_image[start..][0..note_size]);
107 }
108
109 pub fn size(mode: model.BuildIdMode) u64 {
110 return desc_offset + descSize(mode);
111 }
112
113 fn descSize(mode: model.BuildIdMode) u64 {
114 return switch (mode) {
115 .none => 0,
116 .fast => fast_desc_size,
117 .sha1 => sha1_desc_size,
118 };
119 }