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 }