lib/tldr/src/formats/elf/relocation/count.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const root = @import("../../../root.zig");
 3 const elf = @import("../root.zig");
 4 const relocation_model = @import("model.zig");
 5 
 6 const Allocator = std.mem.Allocator;
 7 const model = root.model;
 8 const format = elf.format;
 9 const output_section = elf.output_section;
10 const rela_size = format.rela_size;
11 const SectionHeader = format.SectionHeader;
12 const ObjectParseOptions = relocation_model.ObjectParseOptions;
13 const RelocationCounts = relocation_model.RelocationCounts;
14 const SectionMetadata = relocation_model.SectionMetadata;
15 const sectionBytes = format.sectionBytes;
16 const stringFromTable = format.stringFromTable;
17 const readU64 = format.readU64;
18 const writeU64 = format.writeU64;
19 const debugOutputIndexForName = output_section.debugOutputIndexForName;
20 
21 fn sectionNameFromTableOrEmpty(section_names: []const u8, section: SectionHeader) []const u8 {
22     return stringFromTable(section_names, section.name_offset) catch "";
23 }
24 
25 pub fn scanSectionMetadata(sections: []const SectionHeader) SectionMetadata {
26     var metadata = SectionMetadata{};
27     for (sections, 0..) |section, index| {
28         if (metadata.symtab_index == null and section.section_type == std.elf.SHT_SYMTAB) metadata.symtab_index = index;
29         if (section.section_type == std.elf.SHT_GROUP) metadata.has_group_sections = true;
30         if (section.section_type == std.elf.SHT_REL or section.section_type == std.elf.SHT_RELA) {
31             metadata.has_relocation_sections = true;
32         }
33     }
34     return metadata;
35 }
36 
37 pub fn countRelocationsBySection(
38     allocator: Allocator,
39     bytes: []const u8,
40     sections: []const SectionHeader,
41     section_names: []const u8,
42     symtab_index: ?usize,
43     parse_options: ObjectParseOptions,
44 ) model.Error!RelocationCounts {
45     if (symtab_index == null) return error.MissingSymbolTable;
46 
47     const relocation_counts = try allocator.alloc(usize, sections.len);
48     errdefer allocator.free(relocation_counts);
49     @memset(relocation_counts, 0);
50 
51     var duplicate_targets = false;
52     for (sections) |section| {
53         if (section.section_type == std.elf.SHT_REL or section.section_type == std.elf.SHT_RELA) {
54             if (try relocationSectionSkipped(section, sections, section_names, parse_options)) continue;
55         }
56         if (section.section_type == std.elf.SHT_REL) return error.UnsupportedRelocation;
57         if (section.section_type != std.elf.SHT_RELA) continue;
58         if (section.entry_size != rela_size or section.size % rela_size != 0) return error.InvalidObject;
59         if (section.info >= sections.len) return error.MissingSection;
60 
61         const rela_bytes = try sectionBytes(bytes, section);
62         const rela_count = rela_bytes.len / rela_size;
63         const effective_count = if (relocationSectionAllNone(rela_bytes)) 0 else rela_count;
64         if (relocation_counts[section.info] != 0 and effective_count != 0) duplicate_targets = true;
65         if (effective_count > std.math.maxInt(usize) - relocation_counts[section.info]) return error.InvalidObject;
66         relocation_counts[section.info] += effective_count;
67     }
68 
69     return .{
70         .counts = relocation_counts,
71         .duplicate_targets = duplicate_targets,
72     };
73 }
74 
75 pub fn relocationSectionSkipped(
76     section: SectionHeader,
77     sections: []const SectionHeader,
78     section_names: []const u8,
79     parse_options: ObjectParseOptions,
80 ) model.Error!bool {
81     if (!parse_options.strip_debug) return false;
82     if (section.info >= sections.len) return error.MissingSection;
83     return debugOutputIndexForName(sectionNameFromTableOrEmpty(section_names, sections[section.info])) != null;
84 }
85 
86 pub fn relocationSectionAllNone(rela_bytes: []const u8) bool {
87     var offset: usize = 0;
88     while (offset < rela_bytes.len) : (offset += rela_size) {
89         if (@as(u32, @truncate(readU64(rela_bytes, offset + 8))) != @backingInt(std.elf.R_X86_64.NONE)) return false;
90     }
91     return true;
92 }