link.Elf: untangle parseObject and parseArchive

from link.Elf, so that they can be used earlier in the pipeline
This commit is contained in:
Andrew Kelley 2024-10-16 18:48:43 -07:00
parent b510c5719f
commit 2dcfa72376
7 changed files with 362 additions and 288 deletions

View File

@ -1398,8 +1398,15 @@ fn parseObject(self: *Elf, obj: link.Input.Object) ParseError!void {
defer tracy.end();
const gpa = self.base.comp.gpa;
const diags = &self.base.comp.link_diags;
const first_eflags = &self.first_eflags;
const target = self.base.comp.root_mod.resolved_target.result;
const debug_fmt_strip = self.base.comp.config.debug_format == .strip;
const default_sym_version = self.default_sym_version;
const file_handles = &self.file_handles;
const handle = obj.file;
const fh = try self.addFileHandle(handle);
const fh = try addFileHandle(gpa, file_handles, handle);
const index: File.Index = @intCast(try self.files.addOne(gpa));
self.files.set(index, .{ .object = .{
@ -1413,7 +1420,7 @@ fn parseObject(self: *Elf, obj: link.Input.Object) ParseError!void {
try self.objects.append(gpa, index);
const object = self.file(index).?.object;
try object.parse(self);
try object.parse(gpa, diags, obj.path, handle, first_eflags, target, debug_fmt_strip, default_sym_version);
}
pub fn openParseArchiveReportingFailure(self: *Elf, path: Path) void {
@ -1427,36 +1434,49 @@ pub fn openParseArchiveReportingFailure(self: *Elf, path: Path) void {
}
pub fn parseArchiveReportingFailure(self: *Elf, obj: link.Input.Object) void {
const gpa = self.base.comp.gpa;
const diags = &self.base.comp.link_diags;
self.parseArchive(obj) catch |err| switch (err) {
const first_eflags = &self.first_eflags;
const target = self.base.comp.root_mod.resolved_target.result;
const debug_fmt_strip = self.base.comp.config.debug_format == .strip;
const default_sym_version = self.default_sym_version;
const file_handles = &self.file_handles;
const files = &self.files;
const objects = &self.objects;
parseArchive(gpa, diags, file_handles, files, first_eflags, target, debug_fmt_strip, default_sym_version, objects, obj) catch |err| switch (err) {
error.LinkFailure => return, // already reported
else => |e| diags.addParseError(obj.path, "failed to parse archive: {s}", .{@errorName(e)}),
};
}
fn parseArchive(self: *Elf, obj: link.Input.Object) ParseError!void {
fn parseArchive(
gpa: Allocator,
diags: *Diags,
file_handles: *std.ArrayListUnmanaged(File.Handle),
files: *std.MultiArrayList(File.Entry),
first_eflags: *?elf.Word,
target: std.Target,
debug_fmt_strip: bool,
default_sym_version: elf.Versym,
objects: *std.ArrayListUnmanaged(File.Index),
obj: link.Input.Object,
) ParseError!void {
const tracy = trace(@src());
defer tracy.end();
const gpa = self.base.comp.gpa;
const handle = obj.file;
const fh = try self.addFileHandle(handle);
var archive: Archive = .{};
const fh = try addFileHandle(gpa, file_handles, obj.file);
var archive = try Archive.parse(gpa, diags, file_handles, obj.path, fh);
defer archive.deinit(gpa);
try archive.parse(self, obj.path, fh);
const objects = try archive.objects.toOwnedSlice(gpa);
defer gpa.free(objects);
for (objects) |extracted| {
const index: File.Index = @intCast(try self.files.addOne(gpa));
self.files.set(index, .{ .object = extracted });
const object = &self.files.items(.data)[index].object;
for (archive.objects) |extracted| {
const index: File.Index = @intCast(try files.addOne(gpa));
files.set(index, .{ .object = extracted });
const object = &files.items(.data)[index].object;
object.index = index;
object.alive = obj.must_link;
try object.parse(self);
try self.objects.append(gpa, index);
try object.parse(gpa, diags, obj.path, obj.file, first_eflags, target, debug_fmt_strip, default_sym_version);
try objects.append(gpa, index);
}
}
@ -1565,46 +1585,6 @@ fn parseDso(
}
}
pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Word) !void {
if (self.first_eflags == null) {
self.first_eflags = e_flags;
return; // there isn't anything to conflict with yet
}
const self_eflags: *elf.Word = &self.first_eflags.?;
switch (self.getTarget().cpu.arch) {
.riscv64 => {
if (e_flags != self_eflags.*) {
const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags);
const self_riscv_eflags: *riscv.RiscvEflags = @ptrCast(self_eflags);
self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc;
self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso;
var any_errors: bool = false;
if (self_riscv_eflags.fabi != riscv_eflags.fabi) {
any_errors = true;
try self.addFileError(
file_index,
"cannot link object files with different float-point ABIs",
.{},
);
}
if (self_riscv_eflags.rve != riscv_eflags.rve) {
any_errors = true;
try self.addFileError(
file_index,
"cannot link object files with different RVEs",
.{},
);
}
if (any_errors) return error.LinkFailure;
}
},
else => {},
}
}
/// When resolving symbols, we approach the problem similarly to `mold`.
/// 1. Resolve symbols across all objects (including those preemptively extracted archives).
/// 2. Resolve symbols across all shared objects.
@ -4704,16 +4684,16 @@ fn fileLookup(files: std.MultiArrayList(File.Entry), index: File.Index) ?File {
};
}
pub fn addFileHandle(self: *Elf, handle: fs.File) !File.HandleIndex {
const gpa = self.base.comp.gpa;
const index: File.HandleIndex = @intCast(self.file_handles.items.len);
const fh = try self.file_handles.addOne(gpa);
fh.* = handle;
return index;
pub fn addFileHandle(
gpa: Allocator,
file_handles: *std.ArrayListUnmanaged(File.Handle),
handle: fs.File,
) Allocator.Error!File.HandleIndex {
try file_handles.append(gpa, handle);
return @intCast(file_handles.items.len - 1);
}
pub fn fileHandle(self: Elf, index: File.HandleIndex) File.Handle {
assert(index < self.file_handles.items.len);
return self.file_handles.items[index];
}
@ -5588,4 +5568,3 @@ const Thunk = @import("Elf/Thunk.zig");
const Value = @import("../Value.zig");
const VerneedSection = synthetic_sections.VerneedSection;
const ZigObject = @import("Elf/ZigObject.zig");
const riscv = @import("riscv.zig");

View File

@ -1,18 +1,29 @@
objects: std.ArrayListUnmanaged(Object) = .empty,
strtab: std.ArrayListUnmanaged(u8) = .empty,
objects: []const Object,
/// '\n'-delimited
strtab: []const u8,
pub fn deinit(self: *Archive, allocator: Allocator) void {
self.objects.deinit(allocator);
self.strtab.deinit(allocator);
pub fn deinit(a: *Archive, gpa: Allocator) void {
gpa.free(a.objects);
gpa.free(a.strtab);
a.* = undefined;
}
pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.HandleIndex) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const diags = &comp.link_diags;
const handle = elf_file.fileHandle(handle_index);
pub fn parse(
gpa: Allocator,
diags: *Diags,
file_handles: *const std.ArrayListUnmanaged(File.Handle),
path: Path,
handle_index: File.HandleIndex,
) !Archive {
const handle = file_handles.items[handle_index];
const size = (try handle.stat()).size;
var objects: std.ArrayListUnmanaged(Object) = .empty;
defer objects.deinit(gpa);
var strtab: std.ArrayListUnmanaged(u8) = .empty;
defer strtab.deinit(gpa);
var pos: usize = elf.ARMAG.len;
while (true) {
if (pos >= size) break;
@ -37,8 +48,8 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.Hand
if (hdr.isSymtab() or hdr.isSymtab64()) continue;
if (hdr.isStrtab()) {
try self.strtab.resize(gpa, obj_size);
const amt = try handle.preadAll(self.strtab.items, pos);
try strtab.resize(gpa, obj_size);
const amt = try handle.preadAll(strtab.items, pos);
if (amt != obj_size) return error.InputOutput;
continue;
}
@ -47,7 +58,7 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.Hand
const name = if (hdr.name()) |name|
name
else if (try hdr.nameOffset()) |off|
self.getString(off)
stringTableLookup(strtab.items, off)
else
unreachable;
@ -70,14 +81,18 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: Path, handle_index: File.Hand
@as(Path, object.path), @as(Path, path),
});
try self.objects.append(gpa, object);
try objects.append(gpa, object);
}
return .{
.objects = try objects.toOwnedSlice(gpa),
.strtab = try strtab.toOwnedSlice(gpa),
};
}
fn getString(self: Archive, off: u32) []const u8 {
assert(off < self.strtab.items.len);
const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
return name[0 .. name.len - 1];
pub fn stringTableLookup(strtab: []const u8, off: u32) [:'\n']const u8 {
const slice = strtab[off..];
return slice[0..mem.indexOfScalar(u8, slice, '\n').? :'\n'];
}
pub fn setArHdr(opts: struct {
@ -290,8 +305,9 @@ const fs = std.fs;
const log = std.log.scoped(.link);
const mem = std.mem;
const Path = std.Build.Cache.Path;
const Allocator = std.mem.Allocator;
const Allocator = mem.Allocator;
const Diags = @import("../../link.zig").Diags;
const Archive = @This();
const Elf = @import("../Elf.zig");
const File = @import("file.zig").File;

View File

@ -102,9 +102,13 @@ pub fn relocsShndx(self: Atom) ?u32 {
return self.relocs_section_index;
}
pub fn priority(self: Atom, elf_file: *Elf) u64 {
const index = self.file(elf_file).?.index();
return (@as(u64, @intCast(index)) << 32) | @as(u64, @intCast(self.input_section_index));
pub fn priority(atom: Atom, elf_file: *Elf) u64 {
const index = atom.file(elf_file).?.index();
return priorityLookup(index, atom.input_section_index);
}
pub fn priorityLookup(file_index: File.Index, input_section_index: u32) u64 {
return (@as(u64, @intCast(file_index)) << 32) | @as(u64, @intCast(input_section_index));
}
/// Returns how much room there is to grow in virtual address space.
@ -255,19 +259,13 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
}
}
pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
const extras = self.extra(elf_file);
return switch (self.file(elf_file).?) {
.shared_object => unreachable,
.linker_defined, .zig_object => &[0]Fde{},
.object => |x| x.fdes.items[extras.fde_start..][0..extras.fde_count],
};
pub fn fdes(atom: Atom, object: *Object) []Fde {
const extras = object.atomExtra(atom.extra_index);
return object.fdes.items[extras.fde_start..][0..extras.fde_count];
}
pub fn markFdesDead(self: Atom, elf_file: *Elf) void {
for (self.fdes(elf_file)) |*fde| {
fde.alive = false;
}
pub fn markFdesDead(self: Atom, object: *Object) void {
for (self.fdes(object)) |*fde| fde.alive = false;
}
pub fn addReloc(self: Atom, alloc: Allocator, reloc: elf.Elf64_Rela, zo: *ZigObject) !void {
@ -946,16 +944,21 @@ fn format2(
atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size,
atom.prev_atom_ref, atom.next_atom_ref,
});
if (atom.fdes(elf_file).len > 0) {
try writer.writeAll(" : fdes{ ");
const extras = atom.extra(elf_file);
for (atom.fdes(elf_file), extras.fde_start..) |fde, i| {
try writer.print("{d}", .{i});
if (!fde.alive) try writer.writeAll("([*])");
if (i - extras.fde_start < extras.fde_count - 1) try writer.writeAll(", ");
}
try writer.writeAll(" }");
}
if (atom.file(elf_file)) |atom_file| switch (atom_file) {
.object => |object| {
if (atom.fdes(object).len > 0) {
try writer.writeAll(" : fdes{ ");
const extras = atom.extra(elf_file);
for (atom.fdes(object), extras.fde_start..) |fde, i| {
try writer.print("{d}", .{i});
if (!fde.alive) try writer.writeAll("([*])");
if (i - extras.fde_start < extras.fde_count - 1) try writer.writeAll(", ");
}
try writer.writeAll(" }");
}
},
else => {},
};
if (!atom.alive) {
try writer.writeAll(" : [*]");
}

View File

@ -37,72 +37,87 @@ num_dynrelocs: u32 = 0,
output_symtab_ctx: Elf.SymtabCtx = .{},
output_ar_state: Archive.ArState = .{},
pub fn deinit(self: *Object, allocator: Allocator) void {
if (self.archive) |*ar| allocator.free(ar.path.sub_path);
allocator.free(self.path.sub_path);
self.shdrs.deinit(allocator);
self.symtab.deinit(allocator);
self.strtab.deinit(allocator);
self.symbols.deinit(allocator);
self.symbols_extra.deinit(allocator);
self.symbols_resolver.deinit(allocator);
self.atoms.deinit(allocator);
self.atoms_indexes.deinit(allocator);
self.atoms_extra.deinit(allocator);
self.comdat_groups.deinit(allocator);
self.comdat_group_data.deinit(allocator);
self.relocs.deinit(allocator);
self.fdes.deinit(allocator);
self.cies.deinit(allocator);
self.eh_frame_data.deinit(allocator);
pub fn deinit(self: *Object, gpa: Allocator) void {
if (self.archive) |*ar| gpa.free(ar.path.sub_path);
gpa.free(self.path.sub_path);
self.shdrs.deinit(gpa);
self.symtab.deinit(gpa);
self.strtab.deinit(gpa);
self.symbols.deinit(gpa);
self.symbols_extra.deinit(gpa);
self.symbols_resolver.deinit(gpa);
self.atoms.deinit(gpa);
self.atoms_indexes.deinit(gpa);
self.atoms_extra.deinit(gpa);
self.comdat_groups.deinit(gpa);
self.comdat_group_data.deinit(gpa);
self.relocs.deinit(gpa);
self.fdes.deinit(gpa);
self.cies.deinit(gpa);
self.eh_frame_data.deinit(gpa);
for (self.input_merge_sections.items) |*isec| {
isec.deinit(allocator);
isec.deinit(gpa);
}
self.input_merge_sections.deinit(allocator);
self.input_merge_sections_indexes.deinit(allocator);
self.input_merge_sections.deinit(gpa);
self.input_merge_sections_indexes.deinit(gpa);
}
pub fn parse(self: *Object, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
const cpu_arch = elf_file.getTarget().cpu.arch;
const handle = elf_file.fileHandle(self.file_handle);
try self.parseCommon(gpa, handle, elf_file);
pub fn parse(
self: *Object,
gpa: Allocator,
diags: *Diags,
/// For error reporting purposes only.
path: Path,
handle: fs.File,
first_eflags: *?elf.Word,
target: std.Target,
debug_fmt_strip: bool,
default_sym_version: elf.Versym,
) !void {
try self.parseCommon(gpa, diags, path, handle, first_eflags, target);
// Append null input merge section
try self.input_merge_sections.append(gpa, .{});
// Allocate atom index 0 to null atom
try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) });
try self.initAtoms(gpa, handle, elf_file);
try self.initSymbols(gpa, elf_file);
try self.initAtoms(gpa, diags, path, handle, debug_fmt_strip, target);
try self.initSymbols(gpa, default_sym_version);
for (self.shdrs.items, 0..) |shdr, i| {
const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue;
if (!atom_ptr.alive) continue;
if ((cpu_arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or
mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame"))
if ((target.cpu.arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or
mem.eql(u8, self.getString(atom_ptr.name_offset), ".eh_frame"))
{
try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file);
try self.parseEhFrame(gpa, handle, @intCast(i), target);
}
}
}
fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void {
fn parseCommon(
self: *Object,
gpa: Allocator,
diags: *Diags,
path: Path,
handle: fs.File,
first_eflags: *?elf.Word,
target: std.Target,
) !void {
const offset = if (self.archive) |ar| ar.offset else 0;
const file_size = (try handle.stat()).size;
const header_buffer = try Elf.preadAllAlloc(allocator, handle, offset, @sizeOf(elf.Elf64_Ehdr));
defer allocator.free(header_buffer);
const header_buffer = try Elf.preadAllAlloc(gpa, handle, offset, @sizeOf(elf.Elf64_Ehdr));
defer gpa.free(header_buffer);
self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*;
const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine();
const em = target.toElfMachine();
if (em != self.header.?.e_machine) {
return elf_file.failFile(self.index, "invalid ELF machine type: {s}", .{
return diags.failParse(path, "invalid ELF machine type: {s}", .{
@tagName(self.header.?.e_machine),
});
}
try elf_file.validateEFlags(self.index, self.header.?.e_flags);
try validateEFlags(diags, path, target, self.header.?.e_flags, first_eflags);
if (self.header.?.e_shnum == 0) return;
@ -110,30 +125,30 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
const shnum = math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow;
const shsize = shnum * @sizeOf(elf.Elf64_Shdr);
if (file_size < offset + shoff or file_size < offset + shoff + shsize) {
return elf_file.failFile(self.index, "corrupt header: section header table extends past the end of file", .{});
return diags.failParse(path, "corrupt header: section header table extends past the end of file", .{});
}
const shdrs_buffer = try Elf.preadAllAlloc(allocator, handle, offset + shoff, shsize);
defer allocator.free(shdrs_buffer);
const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, offset + shoff, shsize);
defer gpa.free(shdrs_buffer);
const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum];
try self.shdrs.appendUnalignedSlice(allocator, shdrs);
try self.shdrs.appendUnalignedSlice(gpa, shdrs);
for (self.shdrs.items) |shdr| {
if (shdr.sh_type != elf.SHT_NOBITS) {
if (file_size < offset + shdr.sh_offset or file_size < offset + shdr.sh_offset + shdr.sh_size) {
return elf_file.failFile(self.index, "corrupt section: extends past the end of file", .{});
return diags.failParse(path, "corrupt section: extends past the end of file", .{});
}
}
}
const shstrtab = try self.preadShdrContentsAlloc(allocator, handle, self.header.?.e_shstrndx);
defer allocator.free(shstrtab);
const shstrtab = try self.preadShdrContentsAlloc(gpa, handle, self.header.?.e_shstrndx);
defer gpa.free(shstrtab);
for (self.shdrs.items) |shdr| {
if (shdr.sh_name >= shstrtab.len) {
return elf_file.failFile(self.index, "corrupt section name offset", .{});
return diags.failParse(path, "corrupt section name offset", .{});
}
}
try self.strtab.appendSlice(allocator, shstrtab);
try self.strtab.appendSlice(gpa, shstrtab);
const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {
elf.SHT_SYMTAB => break @as(u32, @intCast(i)),
@ -144,19 +159,19 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
const shdr = self.shdrs.items[index];
self.first_global = shdr.sh_info;
const raw_symtab = try self.preadShdrContentsAlloc(allocator, handle, index);
defer allocator.free(raw_symtab);
const raw_symtab = try self.preadShdrContentsAlloc(gpa, handle, index);
defer gpa.free(raw_symtab);
const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch {
return elf_file.failFile(self.index, "symbol table not evenly divisible", .{});
return diags.failParse(path, "symbol table not evenly divisible", .{});
};
const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
const strtab_bias = @as(u32, @intCast(self.strtab.items.len));
const strtab = try self.preadShdrContentsAlloc(allocator, handle, shdr.sh_link);
defer allocator.free(strtab);
try self.strtab.appendSlice(allocator, strtab);
const strtab = try self.preadShdrContentsAlloc(gpa, handle, shdr.sh_link);
defer gpa.free(strtab);
try self.strtab.appendSlice(gpa, strtab);
try self.symtab.ensureUnusedCapacity(allocator, symtab.len);
try self.symtab.ensureUnusedCapacity(gpa, symtab.len);
for (symtab) |sym| {
const out_sym = self.symtab.addOneAssumeCapacity();
out_sym.* = sym;
@ -168,15 +183,56 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
}
}
fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const debug_fmt_strip = comp.config.debug_format == .strip;
const target = comp.root_mod.resolved_target.result;
fn validateEFlags(
diags: *Diags,
path: Path,
target: std.Target,
e_flags: elf.Word,
first_eflags: *?elf.Word,
) error{LinkFailure}!void {
if (first_eflags.*) |*self_eflags| {
switch (target.cpu.arch) {
.riscv64 => {
if (e_flags != self_eflags.*) {
const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags);
const self_riscv_eflags: *riscv.RiscvEflags = @ptrCast(self_eflags);
self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc;
self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso;
var any_errors: bool = false;
if (self_riscv_eflags.fabi != riscv_eflags.fabi) {
any_errors = true;
diags.addParseError(path, "cannot link object files with different float-point ABIs", .{});
}
if (self_riscv_eflags.rve != riscv_eflags.rve) {
any_errors = true;
diags.addParseError(path, "cannot link object files with different RVEs", .{});
}
if (any_errors) return error.LinkFailure;
}
},
else => {},
}
} else {
first_eflags.* = e_flags;
}
}
fn initAtoms(
self: *Object,
gpa: Allocator,
diags: *Diags,
path: Path,
handle: fs.File,
debug_fmt_strip: bool,
target: std.Target,
) !void {
const shdrs = self.shdrs.items;
try self.atoms.ensureTotalCapacityPrecise(allocator, shdrs.len);
try self.atoms_extra.ensureTotalCapacityPrecise(allocator, shdrs.len * @sizeOf(Atom.Extra));
try self.atoms_indexes.ensureTotalCapacityPrecise(allocator, shdrs.len);
try self.atoms_indexes.resize(allocator, shdrs.len);
try self.atoms.ensureTotalCapacityPrecise(gpa, shdrs.len);
try self.atoms_extra.ensureTotalCapacityPrecise(gpa, shdrs.len * @sizeOf(Atom.Extra));
try self.atoms_indexes.ensureTotalCapacityPrecise(gpa, shdrs.len);
try self.atoms_indexes.resize(gpa, shdrs.len);
@memset(self.atoms_indexes.items, 0);
for (shdrs, 0..) |shdr, i| {
@ -201,24 +257,24 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
};
const shndx: u32 = @intCast(i);
const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
defer allocator.free(group_raw_data);
const group_raw_data = try self.preadShdrContentsAlloc(gpa, handle, shndx);
defer gpa.free(group_raw_data);
const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch {
return elf_file.failFile(self.index, "corrupt section group: not evenly divisible ", .{});
return diags.failParse(path, "corrupt section group: not evenly divisible ", .{});
};
if (group_nmembers == 0) {
return elf_file.failFile(self.index, "corrupt section group: empty section", .{});
return diags.failParse(path, "corrupt section group: empty section", .{});
}
const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
if (group_members[0] != elf.GRP_COMDAT) {
return elf_file.failFile(self.index, "corrupt section group: unknown SHT_GROUP format", .{});
return diags.failParse(path, "corrupt section group: unknown SHT_GROUP format", .{});
}
const group_start: u32 = @intCast(self.comdat_group_data.items.len);
try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]);
try self.comdat_group_data.appendUnalignedSlice(gpa, group_members[1..]);
const comdat_group_index = try self.addComdatGroup(allocator);
const comdat_group_index = try self.addComdatGroup(gpa);
const comdat_group = self.comdatGroup(comdat_group_index);
comdat_group.* = .{
.signature_off = group_signature,
@ -242,8 +298,8 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
const shndx: u32 = @intCast(i);
if (self.skipShdr(shndx, debug_fmt_strip)) continue;
const size, const alignment = if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) blk: {
const data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
defer allocator.free(data);
const data = try self.preadShdrContentsAlloc(gpa, handle, shndx);
defer gpa.free(data);
const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
break :blk .{ chdr.ch_size, Alignment.fromNonzeroByteUnits(chdr.ch_addralign) };
} else .{ shdr.sh_size, Alignment.fromNonzeroByteUnits(shdr.sh_addralign) };
@ -263,13 +319,13 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
elf.SHT_REL, elf.SHT_RELA => {
const atom_index = self.atoms_indexes.items[shdr.sh_info];
if (self.atom(atom_index)) |atom_ptr| {
const relocs = try self.preadRelocsAlloc(allocator, handle, @intCast(i));
defer allocator.free(relocs);
const relocs = try self.preadRelocsAlloc(gpa, handle, @intCast(i));
defer gpa.free(relocs);
atom_ptr.relocs_section_index = @intCast(i);
const rel_index: u32 = @intCast(self.relocs.items.len);
const rel_count: u32 = @intCast(relocs.len);
self.setAtomFields(atom_ptr, .{ .rel_index = rel_index, .rel_count = rel_count });
try self.relocs.appendUnalignedSlice(allocator, relocs);
try self.relocs.appendUnalignedSlice(gpa, relocs);
if (target.cpu.arch == .riscv64) {
sortRelocs(self.relocs.items[rel_index..][0..rel_count]);
}
@ -293,14 +349,18 @@ fn skipShdr(self: *Object, index: u32, debug_fmt_strip: bool) bool {
return ignore;
}
fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
fn initSymbols(
self: *Object,
gpa: Allocator,
default_sym_version: elf.Versym,
) !void {
const first_global = self.first_global orelse self.symtab.items.len;
const nglobals = self.symtab.items.len - first_global;
try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len);
try self.symbols_extra.ensureTotalCapacityPrecise(allocator, self.symtab.items.len * @sizeOf(Symbol.Extra));
try self.symbols_resolver.ensureTotalCapacityPrecise(allocator, nglobals);
self.symbols_resolver.resize(allocator, nglobals) catch unreachable;
try self.symbols.ensureTotalCapacityPrecise(gpa, self.symtab.items.len);
try self.symbols_extra.ensureTotalCapacityPrecise(gpa, self.symtab.items.len * @sizeOf(Symbol.Extra));
try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nglobals);
self.symbols_resolver.resize(gpa, nglobals) catch unreachable;
@memset(self.symbols_resolver.items, 0);
for (self.symtab.items, 0..) |sym, i| {
@ -310,7 +370,7 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
sym_ptr.name_offset = sym.st_name;
sym_ptr.esym_index = @intCast(i);
sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{});
sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else .LOCAL;
sym_ptr.version_index = if (i >= first_global) default_sym_version else .LOCAL;
sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK;
if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) {
sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index };
@ -318,24 +378,30 @@ fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
}
}
fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void {
fn parseEhFrame(
self: *Object,
gpa: Allocator,
handle: fs.File,
shndx: u32,
target: std.Target,
) !void {
const relocs_shndx = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) {
elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u32, @intCast(i)),
else => {},
} else null;
const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx);
defer allocator.free(raw);
const data_start = @as(u32, @intCast(self.eh_frame_data.items.len));
try self.eh_frame_data.appendSlice(allocator, raw);
const raw = try self.preadShdrContentsAlloc(gpa, handle, shndx);
defer gpa.free(raw);
const data_start: u32 = @intCast(self.eh_frame_data.items.len);
try self.eh_frame_data.appendSlice(gpa, raw);
const relocs = if (relocs_shndx) |index|
try self.preadRelocsAlloc(allocator, handle, index)
try self.preadRelocsAlloc(gpa, handle, index)
else
&[0]elf.Elf64_Rela{};
defer allocator.free(relocs);
const rel_start = @as(u32, @intCast(self.relocs.items.len));
try self.relocs.appendUnalignedSlice(allocator, relocs);
if (elf_file.getTarget().cpu.arch == .riscv64) {
defer gpa.free(relocs);
const rel_start: u32 = @intCast(self.relocs.items.len);
try self.relocs.appendUnalignedSlice(gpa, relocs);
if (target.cpu.arch == .riscv64) {
sortRelocs(self.relocs.items[rel_start..][0..relocs.len]);
}
const fdes_start = self.fdes.items.len;
@ -345,11 +411,11 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
while (try it.next()) |rec| {
const rel_range = filterRelocs(self.relocs.items[rel_start..][0..relocs.len], rec.offset, rec.size + 4);
switch (rec.tag) {
.cie => try self.cies.append(allocator, .{
.cie => try self.cies.append(gpa, .{
.offset = data_start + rec.offset,
.size = rec.size,
.rel_index = rel_start + @as(u32, @intCast(rel_range.start)),
.rel_num = @as(u32, @intCast(rel_range.len)),
.rel_num = @intCast(rel_range.len),
.input_section_index = shndx,
.file_index = self.index,
}),
@ -361,12 +427,12 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
// this can happen for object files built with -r flag by the linker.
continue;
}
try self.fdes.append(allocator, .{
try self.fdes.append(gpa, .{
.offset = data_start + rec.offset,
.size = rec.size,
.cie_index = undefined,
.rel_index = rel_start + @as(u32, @intCast(rel_range.start)),
.rel_num = @as(u32, @intCast(rel_range.len)),
.rel_num = @intCast(rel_range.len),
.input_section_index = shndx,
.file_index = self.index,
});
@ -376,7 +442,7 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
// Tie each FDE to its CIE
for (self.fdes.items[fdes_start..]) |*fde| {
const cie_ptr = fde.offset + 4 - fde.ciePointer(elf_file);
const cie_ptr = fde.offset + 4 - fde.ciePointer(self);
const cie_index = for (self.cies.items[cies_start..], cies_start..) |cie, cie_index| {
if (cie.offset == cie_ptr) break @as(u32, @intCast(cie_index));
} else {
@ -392,26 +458,26 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
// Tie each FDE record to its matching atom
const SortFdes = struct {
pub fn lessThan(ctx: *Elf, lhs: Fde, rhs: Fde) bool {
pub fn lessThan(ctx: *Object, lhs: Fde, rhs: Fde) bool {
const lhs_atom = lhs.atom(ctx);
const rhs_atom = rhs.atom(ctx);
return lhs_atom.priority(ctx) < rhs_atom.priority(ctx);
return Atom.priorityLookup(ctx.index, lhs_atom.input_section_index) < Atom.priorityLookup(ctx.index, rhs_atom.input_section_index);
}
};
mem.sort(Fde, self.fdes.items[fdes_start..], elf_file, SortFdes.lessThan);
mem.sort(Fde, self.fdes.items[fdes_start..], self, SortFdes.lessThan);
// Create a back-link from atom to FDEs
var i: u32 = @as(u32, @intCast(fdes_start));
var i: u32 = @intCast(fdes_start);
while (i < self.fdes.items.len) {
const fde = self.fdes.items[i];
const atom_ptr = fde.atom(elf_file);
const atom_ptr = fde.atom(self);
const start = i;
i += 1;
while (i < self.fdes.items.len) : (i += 1) {
const next_fde = self.fdes.items[i];
if (atom_ptr.atom_index != next_fde.atom(elf_file).atom_index) break;
if (atom_ptr.atom_index != next_fde.atom(self).atom_index) break;
}
atom_ptr.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);
self.setAtomFields(atom_ptr, .{ .fde_start = start, .fde_count = i - start });
}
}
@ -904,7 +970,7 @@ pub fn markComdatGroupsDead(self: *Object, elf_file: *Elf) void {
const atom_index = self.atoms_indexes.items[shndx];
if (self.atom(atom_index)) |atom_ptr| {
atom_ptr.alive = false;
atom_ptr.markFdesDead(elf_file);
atom_ptr.markFdesDead(self);
}
}
}
@ -970,10 +1036,13 @@ pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void {
}
}
pub fn parseAr(self: *Object, elf_file: *Elf) !void {
pub fn parseAr(self: *Object, path: Path, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
const diags = &elf_file.base.comp.link_diags;
const handle = elf_file.fileHandle(self.file_handle);
try self.parseCommon(gpa, handle, elf_file);
const first_eflags = &elf_file.first_eflags;
const target = elf_file.base.comp.root_mod.resolved_target.result;
try self.parseCommon(gpa, diags, path, handle, first_eflags, target);
}
pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
@ -1000,7 +1069,7 @@ pub fn updateArSize(self: *Object, elf_file: *Elf) !void {
pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
const offset: u64 = if (self.archive) |ar| ar.offset else 0;
const name = std.fs.path.basename(self.path.sub_path);
const name = fs.path.basename(self.path.sub_path);
const hdr = Archive.setArHdr(.{
.name = if (name.len <= Archive.max_member_name_len)
.{ .name = name }
@ -1136,8 +1205,8 @@ pub fn resolveSymbol(self: Object, index: Symbol.Index, elf_file: *Elf) Elf.Ref
return elf_file.resolver.get(resolv).?;
}
fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index {
try self.symbols.ensureUnusedCapacity(allocator, 1);
fn addSymbol(self: *Object, gpa: Allocator) !Symbol.Index {
try self.symbols.ensureUnusedCapacity(gpa, 1);
return self.addSymbolAssumeCapacity();
}
@ -1147,9 +1216,9 @@ fn addSymbolAssumeCapacity(self: *Object) Symbol.Index {
return index;
}
pub fn addSymbolExtra(self: *Object, allocator: Allocator, extra: Symbol.Extra) !u32 {
pub fn addSymbolExtra(self: *Object, gpa: Allocator, extra: Symbol.Extra) !u32 {
const fields = @typeInfo(Symbol.Extra).@"struct".fields;
try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
try self.symbols_extra.ensureUnusedCapacity(gpa, fields.len);
return self.addSymbolExtraAssumeCapacity(extra);
}
@ -1198,27 +1267,27 @@ pub fn getString(self: Object, off: u32) [:0]const u8 {
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
}
fn addString(self: *Object, allocator: Allocator, str: []const u8) !u32 {
fn addString(self: *Object, gpa: Allocator, str: []const u8) !u32 {
const off: u32 = @intCast(self.strtab.items.len);
try self.strtab.ensureUnusedCapacity(allocator, str.len + 1);
try self.strtab.ensureUnusedCapacity(gpa, str.len + 1);
self.strtab.appendSliceAssumeCapacity(str);
self.strtab.appendAssumeCapacity(0);
return off;
}
/// Caller owns the memory.
fn preadShdrContentsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, index: u32) ![]u8 {
fn preadShdrContentsAlloc(self: Object, gpa: Allocator, handle: fs.File, index: u32) ![]u8 {
assert(index < self.shdrs.items.len);
const offset = if (self.archive) |ar| ar.offset else 0;
const shdr = self.shdrs.items[index];
const sh_offset = math.cast(u64, shdr.sh_offset) orelse return error.Overflow;
const sh_size = math.cast(u64, shdr.sh_size) orelse return error.Overflow;
return Elf.preadAllAlloc(allocator, handle, offset + sh_offset, sh_size);
return Elf.preadAllAlloc(gpa, handle, offset + sh_offset, sh_size);
}
/// Caller owns the memory.
fn preadRelocsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, shndx: u32) ![]align(1) const elf.Elf64_Rela {
const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx);
fn preadRelocsAlloc(self: Object, gpa: Allocator, handle: fs.File, shndx: u32) ![]align(1) const elf.Elf64_Rela {
const raw = try self.preadShdrContentsAlloc(gpa, handle, shndx);
const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela));
return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
}
@ -1230,9 +1299,9 @@ const AddAtomArgs = struct {
alignment: Alignment,
};
fn addAtom(self: *Object, allocator: Allocator, args: AddAtomArgs) !Atom.Index {
try self.atoms.ensureUnusedCapacity(allocator, 1);
try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
fn addAtom(self: *Object, gpa: Allocator, args: AddAtomArgs) !Atom.Index {
try self.atoms.ensureUnusedCapacity(gpa, 1);
try self.atoms_extra.ensureUnusedCapacity(gpa, @sizeOf(Atom.Extra));
return self.addAtomAssumeCapacity(args);
}
@ -1257,9 +1326,9 @@ pub fn atom(self: *Object, atom_index: Atom.Index) ?*Atom {
return &self.atoms.items[atom_index];
}
pub fn addAtomExtra(self: *Object, allocator: Allocator, extra: Atom.Extra) !u32 {
pub fn addAtomExtra(self: *Object, gpa: Allocator, extra: Atom.Extra) !u32 {
const fields = @typeInfo(Atom.Extra).@"struct".fields;
try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
try self.atoms_extra.ensureUnusedCapacity(gpa, fields.len);
return self.addAtomExtraAssumeCapacity(extra);
}
@ -1308,9 +1377,9 @@ fn setAtomFields(o: *Object, atom_ptr: *Atom, opts: Atom.Extra.AsOptionals) void
o.setAtomExtra(atom_ptr.extra_index, extras);
}
fn addInputMergeSection(self: *Object, allocator: Allocator) !Merge.InputSection.Index {
fn addInputMergeSection(self: *Object, gpa: Allocator) !Merge.InputSection.Index {
const index: Merge.InputSection.Index = @intCast(self.input_merge_sections.items.len);
const msec = try self.input_merge_sections.addOne(allocator);
const msec = try self.input_merge_sections.addOne(gpa);
msec.* = .{};
return index;
}
@ -1320,9 +1389,9 @@ fn inputMergeSection(self: *Object, index: Merge.InputSection.Index) ?*Merge.Inp
return &self.input_merge_sections.items[index];
}
fn addComdatGroup(self: *Object, allocator: Allocator) !Elf.ComdatGroup.Index {
fn addComdatGroup(self: *Object, gpa: Allocator) !Elf.ComdatGroup.Index {
const index = @as(Elf.ComdatGroup.Index, @intCast(self.comdat_groups.items.len));
_ = try self.comdat_groups.addOne(allocator);
_ = try self.comdat_groups.addOne(gpa);
return index;
}
@ -1516,8 +1585,9 @@ const log = std.log.scoped(.link);
const math = std.math;
const mem = std.mem;
const Path = std.Build.Cache.Path;
const Allocator = mem.Allocator;
const Allocator = std.mem.Allocator;
const Diags = @import("../../link.zig").Diags;
const Archive = @import("Archive.zig");
const Atom = @import("Atom.zig");
const AtomList = @import("AtomList.zig");
@ -1528,3 +1598,4 @@ const File = @import("file.zig").File;
const Merge = @import("Merge.zig");
const Symbol = @import("Symbol.zig");
const Alignment = Atom.Alignment;
const riscv = @import("../riscv.zig");

View File

@ -19,18 +19,16 @@ pub const Fde = struct {
return base + fde.out_offset;
}
pub fn data(fde: Fde, elf_file: *Elf) []u8 {
const object = elf_file.file(fde.file_index).?.object;
pub fn data(fde: Fde, object: *Object) []u8 {
return object.eh_frame_data.items[fde.offset..][0..fde.calcSize()];
}
pub fn cie(fde: Fde, elf_file: *Elf) Cie {
const object = elf_file.file(fde.file_index).?.object;
pub fn cie(fde: Fde, object: *Object) Cie {
return object.cies.items[fde.cie_index];
}
pub fn ciePointer(fde: Fde, elf_file: *Elf) u32 {
const fde_data = fde.data(elf_file);
pub fn ciePointer(fde: Fde, object: *Object) u32 {
const fde_data = fde.data(object);
return std.mem.readInt(u32, fde_data[4..8], .little);
}
@ -38,16 +36,14 @@ pub const Fde = struct {
return fde.size + 4;
}
pub fn atom(fde: Fde, elf_file: *Elf) *Atom {
const object = elf_file.file(fde.file_index).?.object;
const rel = fde.relocs(elf_file)[0];
pub fn atom(fde: Fde, object: *Object) *Atom {
const rel = fde.relocs(object)[0];
const sym = object.symtab.items[rel.r_sym()];
const atom_index = object.atoms_indexes.items[sym.st_shndx];
return object.atom(atom_index).?;
}
pub fn relocs(fde: Fde, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
const object = elf_file.file(fde.file_index).?.object;
pub fn relocs(fde: Fde, object: *Object) []const elf.Elf64_Rela {
return object.relocs.items[fde.rel_index..][0..fde.rel_num];
}
@ -87,7 +83,8 @@ pub const Fde = struct {
const fde = ctx.fde;
const elf_file = ctx.elf_file;
const base_addr = fde.address(elf_file);
const atom_name = fde.atom(elf_file).name(elf_file);
const object = elf_file.file(fde.file_index).?.object;
const atom_name = fde.atom(object).name(elf_file);
try writer.print("@{x} : size({x}) : cie({d}) : {s}", .{
base_addr + fde.out_offset,
fde.calcSize(),
@ -306,7 +303,7 @@ pub fn calcEhFrameRelocs(elf_file: *Elf) usize {
}
for (object.fdes.items) |fde| {
if (!fde.alive) continue;
count += fde.relocs(elf_file).len;
count += fde.relocs(object).len;
}
}
return count;
@ -369,16 +366,16 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
for (object.fdes.items) |fde| {
if (!fde.alive) continue;
const contents = fde.data(elf_file);
const contents = fde.data(object);
std.mem.writeInt(
i32,
contents[4..8],
@truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(elf_file).out_offset))),
@truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(object).out_offset))),
.little,
);
for (fde.relocs(elf_file)) |rel| {
for (fde.relocs(object)) |rel| {
const ref = object.resolveSymbol(rel.r_sym(), elf_file);
const sym = elf_file.symbol(ref).?;
resolveReloc(fde, sym, rel, elf_file, contents) catch |err| switch (err) {
@ -412,12 +409,12 @@ pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void {
for (object.fdes.items) |fde| {
if (!fde.alive) continue;
const contents = fde.data(elf_file);
const contents = fde.data(object);
std.mem.writeInt(
i32,
contents[4..8],
@truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(elf_file).out_offset))),
@truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(object).out_offset))),
.little,
);
@ -490,7 +487,7 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
for (object.fdes.items) |fde| {
if (!fde.alive) continue;
for (fde.relocs(elf_file)) |rel| {
for (fde.relocs(object)) |rel| {
const ref = object.resolveSymbol(rel.r_sym(), elf_file);
const sym = elf_file.symbol(ref).?;
const r_offset = fde.address(elf_file) + rel.r_offset - fde.offset;
@ -548,7 +545,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
for (object.fdes.items) |fde| {
if (!fde.alive) continue;
const relocs = fde.relocs(elf_file);
const relocs = fde.relocs(object);
assert(relocs.len > 0); // Should this be an error? Things are completely broken anyhow if this trips...
const rel = relocs[0];
const ref = object.resolveSymbol(rel.r_sym(), elf_file);

View File

@ -103,15 +103,20 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
assert(atom.visited);
const file = atom.file(elf_file).?;
for (atom.fdes(elf_file)) |fde| {
for (fde.relocs(elf_file)[1..]) |rel| {
const ref = file.resolveSymbol(rel.r_sym(), elf_file);
const target_sym = elf_file.symbol(ref) orelse continue;
const target_atom = target_sym.atom(elf_file) orelse continue;
target_atom.alive = true;
gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
if (markAtom(target_atom)) markLive(target_atom, elf_file);
}
switch (file) {
.object => |object| {
for (atom.fdes(object)) |fde| {
for (fde.relocs(object)[1..]) |rel| {
const ref = file.resolveSymbol(rel.r_sym(), elf_file);
const target_sym = elf_file.symbol(ref) orelse continue;
const target_atom = target_sym.atom(elf_file) orelse continue;
target_atom.alive = true;
gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
if (markAtom(target_atom)) markLive(target_atom, elf_file);
}
}
},
else => {},
}
for (atom.relocs(elf_file)) |rel| {
@ -135,23 +140,25 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {
}
}
fn prune(elf_file: *Elf) void {
const pruneInFile = struct {
fn pruneInFile(file: File, ef: *Elf) void {
for (file.atoms()) |atom_index| {
const atom = file.atom(atom_index) orelse continue;
if (atom.alive and !atom.visited) {
atom.alive = false;
atom.markFdesDead(ef);
}
fn pruneInFile(file: File) void {
for (file.atoms()) |atom_index| {
const atom = file.atom(atom_index) orelse continue;
if (atom.alive and !atom.visited) {
atom.alive = false;
switch (file) {
.object => |object| atom.markFdesDead(object),
else => {},
}
}
}.pruneInFile;
}
}
fn prune(elf_file: *Elf) void {
if (elf_file.zigObjectPtr()) |zo| {
pruneInFile(zo.asFile(), elf_file);
pruneInFile(zo.asFile());
}
for (elf_file.objects.items) |index| {
pruneInFile(elf_file.file(index).?, elf_file);
pruneInFile(elf_file.file(index).?);
}
}

View File

@ -233,8 +233,10 @@ fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: Path) void {
fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
const gpa = elf_file.base.comp.gpa;
const file_handles = &elf_file.file_handles;
const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
const fh = try elf_file.addFileHandle(handle);
const fh = try Elf.addFileHandle(gpa, file_handles, handle);
const index: File.Index = @intCast(try elf_file.files.addOne(gpa));
elf_file.files.set(index, .{ .object = .{
@ -248,27 +250,26 @@ fn parseObjectStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
try elf_file.objects.append(gpa, index);
const object = elf_file.file(index).?.object;
try object.parseAr(elf_file);
try object.parseAr(path, elf_file);
}
fn parseArchiveStaticLib(elf_file: *Elf, path: Path) Elf.ParseError!void {
const gpa = elf_file.base.comp.gpa;
const diags = &elf_file.base.comp.link_diags;
const file_handles = &elf_file.file_handles;
const handle = try path.root_dir.handle.openFile(path.sub_path, .{});
const fh = try elf_file.addFileHandle(handle);
const fh = try Elf.addFileHandle(gpa, file_handles, handle);
var archive = Archive{};
var archive = try Archive.parse(gpa, diags, file_handles, path, fh);
defer archive.deinit(gpa);
try archive.parse(elf_file, path, fh);
const objects = try archive.objects.toOwnedSlice(gpa);
defer gpa.free(objects);
for (objects) |extracted| {
const index = @as(File.Index, @intCast(try elf_file.files.addOne(gpa)));
for (archive.objects) |extracted| {
const index: File.Index = @intCast(try elf_file.files.addOne(gpa));
elf_file.files.set(index, .{ .object = extracted });
const object = &elf_file.files.items(.data)[index].object;
object.index = index;
try object.parseAr(elf_file);
try object.parseAr(path, elf_file);
try elf_file.objects.append(gpa, index);
}
}