Skip to documentation
SLOP

tiny.tldr.formats.elf.merge

Reference tiny.tldr formats elf merge

Defined in formats.elf.

API (19)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callsformats.elfmerge
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/tldr/src/formats/elf/merge/fixed.zig:60

zig
pub const Fixed = struct {    pieces: Map = .empty,    pub fn deinit(self: *Fixed, allocator: Allocator) void {        self.pieces.deinit(allocator);    }    pub fn collect(        self: *Fixed,        allocator: Allocator,        object: ObjectFile,        section: SectionHeader,        section_index: usize,        output_sections: *[output_section_count]OutputSection,        merge_sections: []MergeSectionLayout,        options: model.LinkOptions,    ) model.Error!void {        if (section.size % section.entry_size != 0) return error.InvalidObject;        if (object.relocationsForSection(section_index).len != 0) return error.UnsupportedRelocation;        try validateAlignment(section.alignment);        const entry_size: usize = @intCast(section.entry_size);        const entry_count: usize = @intCast(section.size / section.entry_size);        const layouts = try allocator.alloc(MergePieceLayout, entry_count);        errdefer allocator.free(layouts);        const output_index = outputIndexForAlloc(section);        const output_index_u8: u8 = @intCast(output_index);        var output = &output_sections[output_index];        const alignment = @max(section.alignment, 1);        output.alignment = @max(output.alignment, alignment);        const bytes = try sectionBytes(object.bytes, section);        for (layouts, 0..) |*piece_layout, index| {            const start = index * entry_size;            const piece_bytes = bytes[start..][0..entry_size];            piece_layout.* = .{                .input_offset = @intCast(start),                .size = section.entry_size,            };            const key: Key = .{                .section_type = section.section_type,                .output_index = output_index_u8,                .entry_size = section.entry_size,                .alignment = alignment,                .bytes = piece_bytes,            };            if (self.pieces.getContext(key, context)) |existing| {                piece_layout.contribution = existing.contribution;                piece_layout.output_intra_offset = existing.intra_offset;                continue;            }            const aligned_offset = alignForwardU64(output.file_size, alignment);            const reserved_size = contributionReserveSize(section.entry_size, alignment, options);            const contribution = SectionContribution.init(                output_index,                aligned_offset,                section.entry_size,                reserved_size,                alignment,            );            try self.pieces.putContext(allocator, key, .{ .contribution = contribution }, context);            piece_layout.contribution = contribution;            output.file_size = aligned_offset + reserved_size;            output.memory_size = output.file_size;        }        merge_sections[section_index] = .{            .pieces = layouts,            .fixed_piece_size = section.entry_size,        };    }};

Source: lib/tldr/src/formats/elf/merge/lookup.zig:10

zig
pub const Piece = struct {    contribution: SectionContribution,    intra_offset: u64,};

Source: lib/tldr/src/formats/elf/merge/start.zig:16

zig
pub const Index = struct {    built: bool = false,    sections: []SectionStarts = &.{},    pub fn deinit(self: *Index, allocator: Allocator) void {        for (self.sections) |section| allocator.free(section.starts);        allocator.free(self.sections);        self.* = .{};    }    pub fn forSection(        self: *Index,        allocator: Allocator,        object: ObjectFile,        section_index: usize,    ) Allocator.Error![]const u64 {        if (!self.built) try self.build(allocator, object);        for (self.sections) |section| {            if (section.section_index == section_index) return section.starts;        }        return &.{};    }    fn build(self: *Index, allocator: Allocator, object: ObjectFile) Allocator.Error!void {        var builders = std.ArrayListUnmanaged(SectionBuilder).empty;        defer builders.deinit(allocator);        errdefer deinitBuilders(allocator, builders.items);        for (object.symbols) |symbol| {            if (symbol.section_index >= object.sections.len) continue;            const section_index: usize = symbol.section_index;            const section = object.sections[section_index];            if (!mergeStringSectionWithoutRelocations(object, section, section_index)) continue;            if (!symbol.isGlobalDefinition()) continue;            const starts = try builderForSection(allocator, &builders, section_index);            try starts.append(allocator, symbol.value);        }        const sections = try allocator.alloc(SectionStarts, builders.items.len);        var initialized_sections: usize = 0;        errdefer {            for (sections[0..initialized_sections]) |section| allocator.free(section.starts);            allocator.free(sections);        }        for (builders.items, sections) |*builder, *section| {            std.mem.sort(u64, builder.starts.items, {}, std.sort.asc(u64));            section.* = .{                .section_index = builder.section_index,                .starts = try builder.starts.toOwnedSlice(allocator),            };            initialized_sections += 1;        }        self.sections = sections;        self.built = true;    }};

Source: lib/tldr/src/formats/elf/merge/string.zig:24

zig
pub const String = struct {    records: std.ArrayListUnmanaged(Record) = .empty,    pending: std.ArrayListUnmanaged(Pending) = .empty,    const Pending = struct {        bytes: []const u8,        external_starts: []const u64,        layout_slot: *MergeSectionLayout,        alignment: u64,        section_type: u32,        output_index: u8,        base: usize = 0,        count: usize = 0,        pieces: []MergePieceLayout = &.{},    };    const ScanContext = struct {        pending: []Pending,        records: []Record,    };    pub fn deinit(self: *String, allocator: Allocator) void {        self.records.deinit(allocator);        self.pending.deinit(allocator);    }    pub fn register(        self: *String,        allocator: Allocator,        object: ObjectFile,        section: SectionHeader,        section_index: usize,        external_starts: []const u64,        output_sections: *[output_section_count]OutputSection,        layout_slot: *MergeSectionLayout,    ) model.Error!void {        if (object.relocationsForSection(section_index).len != 0) return error.UnsupportedRelocation;        const bytes = try sectionBytes(object.bytes, section);        if (bytes.len == 0) return;        if (bytes[bytes.len - 1] != 0) return error.InvalidObject;        const output_index = outputIndexForAlloc(section);        var output = &output_sections[output_index];        const alignment = @max(section.alignment, 1);        output.alignment = @max(output.alignment, alignment);        const starts = if (external_starts.len != 0)            try allocator.dupe(u64, external_starts)        else            external_starts;        try self.pending.append(allocator, .{            .bytes = bytes,            .external_starts = starts,            .layout_slot = layout_slot,            .alignment = alignment,            .section_type = section.section_type,            .output_index = @intCast(output_index),        });    }    pub fn finish(        self: *String,        allocator: Allocator,        output_sections: *[output_section_count]OutputSection,        options: model.LinkOptions,    ) model.Error!void {        try self.materialize(allocator, options);        try target.assign(allocator, output_sections, self.records.items, options);    }    fn materialize(self: *String, allocator: Allocator, options: model.LinkOptions) model.Error!void {        if (self.pending.items.len == 0) return;        const pending = self.pending.items;        var total_bytes: usize = 0;        for (pending) |entry| total_bytes += entry.bytes.len;        const requested_workers = if (options.max_link_jobs != 0)            options.max_link_jobs        else            total_bytes / scan_bytes_per_worker;        const workers = if (total_bytes >= parallel_scan_threshold)            parallel.chooseWorkers(pending.len, requested_workers)        else            1;        var count_context = ScanContext{ .pending = pending, .records = &.{} };        if (workers <= 1) {            for (pending, 0..) |_, index| countPending(&count_context, 0, index);        } else {            parallel.forItems(pending.len, workers, &count_context, countPending);        }        var total: usize = 0;        for (pending) |*entry| {            entry.base = total;            total += entry.count;            entry.pieces = try allocator.alloc(MergePieceLayout, entry.count);            entry.layout_slot.* = .{ .pieces = entry.pieces };        }        if (std.math.cast(u32, total) == null) return error.InvalidObject;        try self.records.resize(allocator, total);        var fill_context = ScanContext{ .pending = pending, .records = self.records.items };        if (workers <= 1) {            for (pending, 0..) |_, index| fillPending(&fill_context, 0, index);        } else {            parallel.forItems(pending.len, workers, &fill_context, fillPending);        }    }    fn countPending(context: *ScanContext, worker: usize, index: usize) void {        _ = worker;        context.pending[index].count = start.count(context.pending[index].bytes);    }    fn fillPending(context: *ScanContext, worker: usize, index: usize) void {        _ = worker;        const entry = context.pending[index];        const records = context.records[entry.base..][0..entry.count];        const bytes = entry.bytes;        var input_offset: usize = 0;        var piece_index: usize = 0;        var external_start_index: usize = 0;        for (bytes, 0..) |byte, byte_index| {            if (byte != 0) continue;            const end = byte_index + 1;            const string_bytes = bytes[input_offset..end];            entry.pieces[piece_index] = .{                .input_offset = @intCast(input_offset),                .size = @intCast(string_bytes.len),            };            records[piece_index] = .{                .ordinal = @intCast(entry.base + piece_index),                .section_type = entry.section_type,                .output_index = entry.output_index,                .alignment = entry.alignment,                .reverse_prefix = record.reversePrefix(string_bytes),                .bytes = string_bytes,                .piece = &entry.pieces[piece_index],                .external_start = start.has(entry.external_starts, &external_start_index, input_offset),            };            piece_index += 1;            input_offset = end;        }    }};
Called byCallsNo direct callersformats.elf.format.binarysectionBytesformats.elf.layout.SectionContributioninitformats.elf.merge.Fixedcollect
Static calls · unresolved targets: 6 · external targets: 3.

Source: lib/tldr/src/formats/elf/merge/lookup.zig:15

zig
pub fn address(    object_layout: ObjectLayout,    object: ObjectFile,    output_sections: []const OutputSection,    section_index: usize,    offset: u64,) ?u64 {    const entry = piece(object_layout, object, section_index, offset) orelse return null;    const output = output_sections[entry.contribution.outputIndex()];    return output.address + entry.contribution.offset + entry.intra_offset;}
Called byCallsNo direct callersformats.elf.mergepieceformats.elf.mergeaddress
Static calls · unresolved targets: 0 · external targets: 1.

Source: lib/tldr/src/formats/elf/merge/lookup.zig:27

zig
pub fn contribution(    object_layout: ObjectLayout,    object: ObjectFile,    section_index: usize,    offset: u64,) ?SectionContribution {    const entry = piece(object_layout, object, section_index, offset) orelse return null;    return entry.contribution;}
Called byCallsNo direct callersformats.elf.mergepieceformats.elf.mergecontribution
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/tldr/src/formats/elf/merge/lookup.zig:37

zig
pub fn piece(    object_layout: ObjectLayout,    object: ObjectFile,    section_index: usize,    offset: u64,) ?Piece {    const merge_section = mergeSectionLayout(object_layout, section_index) orelse return null;    const section = object.sections[section_index];    if (offset >= section.size) return null;    if (merge_section.fixed_piece_size != 0) {        const piece_index: usize = @intCast(offset / merge_section.fixed_piece_size);        if (piece_index >= merge_section.pieces.len) return null;        const fixed_piece = merge_section.pieces[piece_index];        return .{            .contribution = fixed_piece.contribution,            .intra_offset = fixed_piece.output_intra_offset + offset % merge_section.fixed_piece_size,        };    }    const string_piece = stringPiece(merge_section.pieces, offset) orelse return null;    return .{        .contribution = string_piece.contribution,        .intra_offset = string_piece.output_intra_offset + offset - string_piece.input_offset,    };}
Called byCallsformats.elf.mergeaddressformats.elf.mergecontributionprivate sourcelib.tldr.src.formats.elf.merge.lookupstringPieceformats.elf.mergepiece
Static calls · unresolved targets: 1 · external targets: 0.

Source: lib/tldr/src/formats/elf/merge/section.zig:9

zig
pub fn ensure(    allocator: Allocator,    object: ObjectFile,    merge_sections: *[]MergeSectionLayout,) Allocator.Error![]MergeSectionLayout {    if (merge_sections.*.len != 0) return merge_sections.*;    const sections = try allocator.alloc(MergeSectionLayout, object.sections.len);    @memset(sections, .{});    merge_sections.* = sections;    return sections;}

Source: lib/tldr/src/formats/elf/merge/section.zig:21

zig
pub fn fixed(section: SectionHeader) bool {    if ((section.flags & std.elf.SHF_ALLOC) == 0) return false;    if ((section.flags & std.elf.SHF_MERGE) == 0) return false;    if ((section.flags & std.elf.SHF_STRINGS) != 0) return false;    if (section.section_type != std.elf.SHT_PROGBITS) return false;    if (section.entry_size == 0) return false;    return true;}

Source: lib/tldr/src/formats/elf/merge/section.zig:30

zig
pub fn string(section: SectionHeader) bool {    if ((section.flags & std.elf.SHF_ALLOC) == 0) return false;    if ((section.flags & std.elf.SHF_MERGE) == 0) return false;    if ((section.flags & std.elf.SHF_STRINGS) == 0) return false;    if (section.section_type != std.elf.SHT_PROGBITS) return false;    if (section.entry_size > 1) return false;    if (section.alignment > 1) return false;    return true;}
Called byCallsNo direct callersprivate sourcelib.tldr.src.formats.elf.merge.start.Indexbuildformats.elf.merge.StartIndexforSection
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/tldr/src/formats/elf/merge/start.zig:83

zig
pub fn collect(    allocator: Allocator,    object: ObjectFile,    section_index: usize,) Allocator.Error![]u64 {    var starts = std.ArrayListUnmanaged(u64).empty;    errdefer starts.deinit(allocator);    for (object.symbols) |symbol| {        if (symbol.section_index != section_index) continue;        if (!symbol.isGlobalDefinition()) continue;        try starts.append(allocator, symbol.value);    }    if (starts.items.len == 0) return &.{};    std.mem.sort(u64, starts.items, {}, std.sort.asc(u64));    return try starts.toOwnedSlice(allocator);}

Source: lib/tldr/src/formats/elf/merge/start.zig:73

zig
pub fn shouldIndex(object: ObjectFile) bool {    var section_count: usize = 0;    for (object.sections, 0..) |section, section_index| {        if (!mergeStringSectionWithoutRelocations(object, section, section_index)) continue;        section_count += 1;        if (section_count > 1) return true;    }    return false;}
Called byCallsNo direct callersprivate sourcelib.tldr.src.formats.elf.merge.startmergeStringSectionWithoutRelocationsformats.elf.mergeshouldIndexStarts
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.tldr.src.formats.elf.merge.string.Stringmaterializeprivate sourcelib.tldr.src.formats.elf.merge.targetassignformats.elf.merge.Stringfinish
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersformats.elf.format.binarysectionBytesformats.elf.merge.Stringregister
Static calls · unresolved targets: 2 · external targets: 2.

Source: lib/tldr/src/formats/elf/merge/root.zig

zig
const fixed_module = @import("fixed.zig");const lookup = @import("lookup.zig");const section = @import("section.zig");const start = @import("start.zig");const string_module = @import("string.zig");pub const Piece = lookup.Piece;pub const Fixed = fixed_module.Fixed;pub const StartIndex = start.Index;pub const String = string_module.String;pub const address = lookup.address;pub const collectStarts = start.collect;pub const contribution = lookup.contribution;pub const ensure = section.ensure;pub const fixed = section.fixed;pub const shouldIndexStarts = start.shouldIndex;pub const piece = lookup.piece;pub const string = section.string;

Source: lib/tldr/src/formats/elf/root.zig:15

zig
pub const merge = @import("merge/root.zig");

Audit

Definitions20
Public names20
Members7
Version26.7.0
Revisiondaab053ee433