elf: introduce SectionChunk - a container of atoms per object file

This commit is contained in:
Jakub Konka
2024-09-01 13:51:08 +02:00
parent 6ec5df3898
commit 1ef96f05eb
2 changed files with 119 additions and 2 deletions

View File

@@ -3555,6 +3555,10 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
}
fn updateSectionSizes(self: *Elf) !void {
for (self.objects.items) |index| {
try self.file(index).?.object.allocateAtoms(self);
}
const slice = self.sections.slice();
for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| {
if (atom_list.items.len == 0) continue;
@@ -5334,8 +5338,9 @@ fn fmtDumpState(
try writer.print("object({d}) : {}", .{ index, object.fmtPath() });
if (!object.alive) try writer.writeAll(" : [*]");
try writer.writeByte('\n');
try writer.print("{}{}{}{}{}\n", .{
try writer.print("{}{}{}{}{}{}\n", .{
object.fmtAtoms(self),
object.fmtSectionChunks(self),
object.fmtCies(self),
object.fmtFdes(self),
object.fmtSymtab(self),

View File

@@ -17,6 +17,7 @@ relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
atoms: std.ArrayListUnmanaged(Atom) = .{},
atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
atoms_extra: std.ArrayListUnmanaged(u32) = .{},
section_chunks: std.ArrayListUnmanaged(SectionChunk) = .{},
comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .{},
comdat_group_data: std.ArrayListUnmanaged(u32) = .{},
@@ -58,6 +59,10 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
self.atoms.deinit(allocator);
self.atoms_indexes.deinit(allocator);
self.atoms_extra.deinit(allocator);
for (self.section_chunks.items) |*chunk| {
chunk.deinit(allocator);
}
self.section_chunks.deinit(allocator);
self.comdat_groups.deinit(allocator);
self.comdat_group_data.deinit(allocator);
self.relocs.deinit(allocator);
@@ -933,11 +938,26 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
const atom_ptr = self.atom(atom_index) orelse continue;
if (!atom_ptr.alive) continue;
const shdr = atom_ptr.inputShdr(elf_file);
_ = try elf_file.initOutputSection(.{
const osec = try elf_file.initOutputSection(.{
.name = self.getString(shdr.sh_name),
.flags = shdr.sh_flags,
.type = shdr.sh_type,
});
const chunk = for (self.section_chunks.items) |*chunk| {
if (chunk.output_section_index == osec) break chunk;
} else blk: {
const chunk = try self.section_chunks.addOne(elf_file.base.comp.gpa);
chunk.* = .{ .output_section_index = osec };
break :blk chunk;
};
try chunk.atoms.append(elf_file.base.comp.gpa, atom_index);
}
}
pub fn allocateAtoms(self: *Object, elf_file: *Elf) !void {
_ = elf_file;
for (self.section_chunks.items) |*chunk| {
chunk.updateSize(self);
}
}
@@ -1427,6 +1447,29 @@ fn formatAtoms(
}
}
pub fn fmtSectionChunks(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatSectionChunks) {
return .{ .data = .{
.object = self,
.elf_file = elf_file,
} };
}
fn formatSectionChunks(
ctx: FormatContext,
comptime unused_fmt_string: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = unused_fmt_string;
_ = options;
const object = ctx.object;
const elf_file = ctx.elf_file;
try writer.writeAll(" section chunks\n");
for (object.section_chunks.items) |chunk| {
try writer.print(" {}\n", .{chunk.fmt(elf_file)});
}
}
pub fn fmtCies(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatCies) {
return .{ .data = .{
.object = self,
@@ -1528,6 +1571,75 @@ const InArchive = struct {
size: u32,
};
const SectionChunk = struct {
value: i64 = 0,
size: u64 = 0,
alignment: Atom.Alignment = .@"1",
output_section_index: u32 = 0,
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
fn deinit(chunk: *SectionChunk, allocator: Allocator) void {
chunk.atoms.deinit(allocator);
}
fn address(chunk: SectionChunk, elf_file: *Elf) i64 {
const shdr = elf_file.sections.items(.shdr)[chunk.output_section_index];
return @as(i64, @intCast(shdr.sh_addr)) + chunk.value;
}
fn updateSize(chunk: *SectionChunk, object: *Object) void {
for (chunk.atoms.items) |atom_index| {
const atom_ptr = object.atom(atom_index).?;
assert(atom_ptr.alive);
const offset = atom_ptr.alignment.forward(chunk.size);
const padding = offset - chunk.size;
atom_ptr.value = @intCast(offset);
chunk.size += padding + atom_ptr.size;
chunk.alignment = chunk.alignment.max(atom_ptr.alignment);
}
}
pub fn format(
chunk: SectionChunk,
comptime unused_fmt_string: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = chunk;
_ = unused_fmt_string;
_ = options;
_ = writer;
@compileError("do not format SectionChunk directly");
}
const FormatCtx = struct { SectionChunk, *Elf };
pub fn fmt(chunk: SectionChunk, elf_file: *Elf) std.fmt.Formatter(format2) {
return .{ .data = .{ chunk, elf_file } };
}
fn format2(
ctx: FormatCtx,
comptime unused_fmt_string: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = unused_fmt_string;
_ = options;
const chunk, const elf_file = ctx;
try writer.print("chunk : @{x} : shdr({d}) : align({x}) : size({x})", .{
chunk.address(elf_file), chunk.output_section_index,
chunk.alignment.toByteUnits() orelse 0, chunk.size,
});
try writer.writeAll(" : atoms{ ");
for (chunk.atoms.items, 0..) |atom_index, i| {
try writer.print("{d}", .{atom_index});
if (i < chunk.atoms.items.len - 1) try writer.writeAll(", ");
}
try writer.writeAll(" }");
}
};
const Object = @This();
const std = @import("std");