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 }