Merge pull request #20873 from ziglang/elf-ownership
elf: clean up resource ownership in the linker
This commit is contained in:
700
src/link/Elf.zig
700
src/link/Elf.zig
File diff suppressed because it is too large
Load Diff
@@ -30,14 +30,17 @@ atom_index: Index = 0,
|
||||
prev_index: Index = 0,
|
||||
next_index: Index = 0,
|
||||
|
||||
/// Flags we use for state tracking.
|
||||
flags: Flags = .{},
|
||||
/// Specifies whether this atom is alive or has been garbage collected.
|
||||
alive: bool = true,
|
||||
|
||||
/// Specifies if the atom has been visited during garbage collection.
|
||||
visited: bool = false,
|
||||
|
||||
extra_index: u32 = 0,
|
||||
|
||||
pub const Alignment = @import("../../InternPool.zig").Alignment;
|
||||
|
||||
pub fn name(self: Atom, elf_file: *Elf) []const u8 {
|
||||
pub fn name(self: Atom, elf_file: *Elf) [:0]const u8 {
|
||||
const file_ptr = self.file(elf_file).?;
|
||||
return switch (file_ptr) {
|
||||
inline else => |x| x.getString(self.name_offset),
|
||||
@@ -45,8 +48,7 @@ pub fn name(self: Atom, elf_file: *Elf) []const u8 {
|
||||
}
|
||||
|
||||
pub fn address(self: Atom, elf_file: *Elf) i64 {
|
||||
const shndx = self.outputShndx() orelse return self.value;
|
||||
const shdr = elf_file.shdrs.items[shndx];
|
||||
const shdr = elf_file.shdrs.items[self.output_section_index];
|
||||
return @as(i64, @intCast(shdr.sh_addr)) + self.value;
|
||||
}
|
||||
|
||||
@@ -55,7 +57,7 @@ pub fn debugTombstoneValue(self: Atom, target: Symbol, elf_file: *Elf) ?u64 {
|
||||
if (msub.alive) return null;
|
||||
}
|
||||
if (target.atom(elf_file)) |atom_ptr| {
|
||||
if (atom_ptr.flags.alive) return null;
|
||||
if (atom_ptr.alive) return null;
|
||||
}
|
||||
const atom_name = self.name(elf_file);
|
||||
if (!mem.startsWith(u8, atom_name, ".debug")) return null;
|
||||
@@ -67,8 +69,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
|
||||
}
|
||||
|
||||
pub fn thunk(self: Atom, elf_file: *Elf) *Thunk {
|
||||
assert(self.flags.thunk);
|
||||
const extras = self.extra(elf_file).?;
|
||||
const extras = self.extra(elf_file);
|
||||
return elf_file.thunk(extras.thunk);
|
||||
}
|
||||
|
||||
@@ -85,11 +86,6 @@ pub fn relocsShndx(self: Atom) ?u32 {
|
||||
return self.relocs_section_index;
|
||||
}
|
||||
|
||||
pub fn outputShndx(self: Atom) ?u32 {
|
||||
if (self.output_section_index == 0) return null;
|
||||
return self.output_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));
|
||||
@@ -99,7 +95,8 @@ pub fn priority(self: Atom, elf_file: *Elf) u64 {
|
||||
/// File offset relocation happens transparently, so it is not included in
|
||||
/// this calculation.
|
||||
pub fn capacity(self: Atom, elf_file: *Elf) u64 {
|
||||
const next_addr = if (elf_file.atom(self.next_index)) |next|
|
||||
const zo = elf_file.zigObjectPtr().?;
|
||||
const next_addr = if (zo.atom(self.next_index)) |next|
|
||||
next.address(elf_file)
|
||||
else
|
||||
std.math.maxInt(u32);
|
||||
@@ -107,8 +104,9 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
|
||||
}
|
||||
|
||||
pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
|
||||
const zo = elf_file.zigObjectPtr().?;
|
||||
// No need to keep a free list node for the last block.
|
||||
const next = elf_file.atom(self.next_index) orelse return false;
|
||||
const next = zo.atom(self.next_index) orelse return false;
|
||||
const cap: u64 = @intCast(next.address(elf_file) - self.address(elf_file));
|
||||
const ideal_cap = Elf.padToIdeal(self.size);
|
||||
if (cap <= ideal_cap) return false;
|
||||
@@ -117,8 +115,9 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
|
||||
}
|
||||
|
||||
pub fn allocate(self: *Atom, elf_file: *Elf) !void {
|
||||
const shdr = &elf_file.shdrs.items[self.outputShndx().?];
|
||||
const meta = elf_file.last_atom_and_free_list_table.getPtr(self.outputShndx().?).?;
|
||||
const zo = elf_file.zigObjectPtr().?;
|
||||
const shdr = &elf_file.shdrs.items[self.output_section_index];
|
||||
const meta = elf_file.last_atom_and_free_list_table.getPtr(self.output_section_index).?;
|
||||
const free_list = &meta.free_list;
|
||||
const last_atom_index = &meta.last_atom_index;
|
||||
const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
|
||||
@@ -137,7 +136,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
|
||||
var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;
|
||||
while (i < free_list.items.len) {
|
||||
const big_atom_index = free_list.items[i];
|
||||
const big_atom = elf_file.atom(big_atom_index).?;
|
||||
const big_atom = zo.atom(big_atom_index).?;
|
||||
// We now have a pointer to a live atom that has too much capacity.
|
||||
// Is it enough that we could fit this new atom?
|
||||
const cap = big_atom.capacity(elf_file);
|
||||
@@ -169,7 +168,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
|
||||
free_list_removal = i;
|
||||
}
|
||||
break :blk @intCast(new_start_vaddr);
|
||||
} else if (elf_file.atom(last_atom_index.*)) |last| {
|
||||
} else if (zo.atom(last_atom_index.*)) |last| {
|
||||
const ideal_capacity = Elf.padToIdeal(last.size);
|
||||
const ideal_capacity_end_vaddr = @as(u64, @intCast(last.value)) + ideal_capacity;
|
||||
const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr);
|
||||
@@ -189,12 +188,12 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
|
||||
});
|
||||
|
||||
const expand_section = if (atom_placement) |placement_index|
|
||||
elf_file.atom(placement_index).?.next_index == 0
|
||||
zo.atom(placement_index).?.next_index == 0
|
||||
else
|
||||
true;
|
||||
if (expand_section) {
|
||||
const needed_size: u64 = @intCast(self.value + @as(i64, @intCast(self.size)));
|
||||
try elf_file.growAllocSection(self.outputShndx().?, needed_size);
|
||||
try elf_file.growAllocSection(self.output_section_index, needed_size);
|
||||
last_atom_index.* = self.atom_index;
|
||||
|
||||
const zig_object = elf_file.zigObjectPtr().?;
|
||||
@@ -214,15 +213,15 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
|
||||
// This function can also reallocate an atom.
|
||||
// In this case we need to "unplug" it from its previous location before
|
||||
// plugging it in to its new location.
|
||||
if (elf_file.atom(self.prev_index)) |prev| {
|
||||
if (zo.atom(self.prev_index)) |prev| {
|
||||
prev.next_index = self.next_index;
|
||||
}
|
||||
if (elf_file.atom(self.next_index)) |next| {
|
||||
if (zo.atom(self.next_index)) |next| {
|
||||
next.prev_index = self.prev_index;
|
||||
}
|
||||
|
||||
if (atom_placement) |big_atom_index| {
|
||||
const big_atom = elf_file.atom(big_atom_index).?;
|
||||
const big_atom = zo.atom(big_atom_index).?;
|
||||
self.prev_index = big_atom_index;
|
||||
self.next_index = big_atom.next_index;
|
||||
big_atom.next_index = self.atom_index;
|
||||
@@ -234,7 +233,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
|
||||
_ = free_list.swapRemove(i);
|
||||
}
|
||||
|
||||
self.flags.alive = true;
|
||||
self.alive = true;
|
||||
}
|
||||
|
||||
pub fn shrink(self: *Atom, elf_file: *Elf) void {
|
||||
@@ -250,9 +249,10 @@ pub fn grow(self: *Atom, elf_file: *Elf) !void {
|
||||
pub fn free(self: *Atom, elf_file: *Elf) void {
|
||||
log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.name(elf_file) });
|
||||
|
||||
const zo = elf_file.zigObjectPtr().?;
|
||||
const comp = elf_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
const shndx = self.outputShndx().?;
|
||||
const shndx = self.output_section_index;
|
||||
const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;
|
||||
const free_list = &meta.free_list;
|
||||
const last_atom_index = &meta.last_atom_index;
|
||||
@@ -272,9 +272,9 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
|
||||
}
|
||||
}
|
||||
|
||||
if (elf_file.atom(last_atom_index.*)) |last_atom| {
|
||||
if (zo.atom(last_atom_index.*)) |last_atom| {
|
||||
if (last_atom.atom_index == self.atom_index) {
|
||||
if (elf_file.atom(self.prev_index)) |_| {
|
||||
if (zo.atom(self.prev_index)) |_| {
|
||||
// TODO shrink the section size here
|
||||
last_atom_index.* = self.prev_index;
|
||||
} else {
|
||||
@@ -283,7 +283,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
|
||||
}
|
||||
}
|
||||
|
||||
if (elf_file.atom(self.prev_index)) |prev| {
|
||||
if (zo.atom(self.prev_index)) |prev| {
|
||||
prev.next_index = self.next_index;
|
||||
if (!already_have_free_list_node and prev.*.freeListEligible(elf_file)) {
|
||||
// The free list is heuristics, it doesn't have to be perfect, so we can
|
||||
@@ -294,7 +294,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
|
||||
self.prev_index = 0;
|
||||
}
|
||||
|
||||
if (elf_file.atom(self.next_index)) |next| {
|
||||
if (zo.atom(self.next_index)) |next| {
|
||||
next.prev_index = self.prev_index;
|
||||
} else {
|
||||
self.next_index = 0;
|
||||
@@ -313,7 +313,7 @@ pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela {
|
||||
switch (self.file(elf_file).?) {
|
||||
.zig_object => |x| return x.relocs.items[shndx].items,
|
||||
.object => |x| {
|
||||
const extras = self.extra(elf_file).?;
|
||||
const extras = self.extra(elf_file);
|
||||
return x.relocs.items[extras.rel_index..][0..extras.rel_count];
|
||||
},
|
||||
else => unreachable,
|
||||
@@ -337,12 +337,12 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
|
||||
var r_addend = rel.r_addend;
|
||||
var r_sym: u32 = 0;
|
||||
switch (target.type(elf_file)) {
|
||||
elf.STT_SECTION => if (target.mergeSubsection(elf_file)) |msub| {
|
||||
elf.STT_SECTION => {
|
||||
r_addend += @intCast(target.address(.{}, elf_file));
|
||||
r_sym = elf_file.sectionSymbolOutputSymtabIndex(msub.mergeSection(elf_file).output_section_index);
|
||||
} else {
|
||||
r_addend += @intCast(target.address(.{}, elf_file));
|
||||
r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?);
|
||||
r_sym = if (target.outputShndx(elf_file)) |osec|
|
||||
elf_file.sectionSymbolOutputSymtabIndex(osec)
|
||||
else
|
||||
0;
|
||||
},
|
||||
else => {
|
||||
r_sym = target.outputSymtabIndex(elf_file) orelse 0;
|
||||
@@ -366,10 +366,12 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
|
||||
}
|
||||
|
||||
pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
|
||||
if (!self.flags.fde) return &[0]Fde{};
|
||||
const extras = self.extra(elf_file).?;
|
||||
const object = self.file(elf_file).?.object;
|
||||
return object.fdes.items[extras.fde_start..][0..extras.fde_count];
|
||||
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 markFdesDead(self: Atom, elf_file: *Elf) void {
|
||||
@@ -712,9 +714,9 @@ fn reportUndefined(
|
||||
{
|
||||
const gop = try undefs.getOrPut(sym_index);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = std.ArrayList(Atom.Index).init(gpa);
|
||||
gop.value_ptr.* = std.ArrayList(Elf.Ref).init(gpa);
|
||||
}
|
||||
try gop.value_ptr.append(self.atom_index);
|
||||
try gop.value_ptr.append(.{ .index = self.atom_index, .file = self.file_index });
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1001,25 +1003,23 @@ const AddExtraOpts = struct {
|
||||
rel_count: ?u32 = null,
|
||||
};
|
||||
|
||||
pub fn addExtra(atom: *Atom, opts: AddExtraOpts, elf_file: *Elf) !void {
|
||||
if (atom.extra(elf_file) == null) {
|
||||
atom.extra_index = try elf_file.addAtomExtra(.{});
|
||||
}
|
||||
var extras = atom.extra(elf_file).?;
|
||||
pub fn addExtra(atom: *Atom, opts: AddExtraOpts, elf_file: *Elf) void {
|
||||
const file_ptr = atom.file(elf_file).?;
|
||||
var extras = file_ptr.atomExtra(atom.extra_index);
|
||||
inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {
|
||||
if (@field(opts, field.name)) |x| {
|
||||
@field(extras, field.name) = x;
|
||||
}
|
||||
}
|
||||
atom.setExtra(extras, elf_file);
|
||||
file_ptr.setAtomExtra(atom.extra_index, extras);
|
||||
}
|
||||
|
||||
pub inline fn extra(atom: Atom, elf_file: *Elf) ?Extra {
|
||||
return elf_file.atomExtra(atom.extra_index);
|
||||
pub inline fn extra(atom: Atom, elf_file: *Elf) Extra {
|
||||
return atom.file(elf_file).?.atomExtra(atom.extra_index);
|
||||
}
|
||||
|
||||
pub inline fn setExtra(atom: Atom, extras: Extra, elf_file: *Elf) void {
|
||||
elf_file.setAtomExtra(atom.extra_index, extras);
|
||||
atom.file(elf_file).?.setAtomExtra(atom.extra_index, extras);
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
@@ -1061,9 +1061,9 @@ fn format2(
|
||||
atom.atom_index, atom.name(elf_file), atom.address(elf_file),
|
||||
atom.output_section_index, atom.alignment, atom.size,
|
||||
});
|
||||
if (atom.flags.fde) {
|
||||
if (atom.fdes(elf_file).len > 0) {
|
||||
try writer.writeAll(" : fdes{ ");
|
||||
const extras = atom.extra(elf_file).?;
|
||||
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("([*])");
|
||||
@@ -1071,27 +1071,13 @@ fn format2(
|
||||
}
|
||||
try writer.writeAll(" }");
|
||||
}
|
||||
if (!atom.flags.alive) {
|
||||
if (!atom.alive) {
|
||||
try writer.writeAll(" : [*]");
|
||||
}
|
||||
}
|
||||
|
||||
pub const Index = u32;
|
||||
|
||||
pub const Flags = packed struct {
|
||||
/// Specifies whether this atom is alive or has been garbage collected.
|
||||
alive: bool = true,
|
||||
|
||||
/// Specifies if the atom has been visited during garbage collection.
|
||||
visited: bool = false,
|
||||
|
||||
/// Whether this atom has a range extension thunk.
|
||||
thunk: bool = false,
|
||||
|
||||
/// Whether this atom has FDE records.
|
||||
fde: bool = false,
|
||||
};
|
||||
|
||||
const x86_64 = struct {
|
||||
fn scanReloc(
|
||||
atom: Atom,
|
||||
|
||||
@@ -1,17 +1,89 @@
|
||||
index: File.Index,
|
||||
|
||||
symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
|
||||
entry_index: ?Symbol.Index = null,
|
||||
dynamic_index: ?Symbol.Index = null,
|
||||
ehdr_start_index: ?Symbol.Index = null,
|
||||
init_array_start_index: ?Symbol.Index = null,
|
||||
init_array_end_index: ?Symbol.Index = null,
|
||||
fini_array_start_index: ?Symbol.Index = null,
|
||||
fini_array_end_index: ?Symbol.Index = null,
|
||||
preinit_array_start_index: ?Symbol.Index = null,
|
||||
preinit_array_end_index: ?Symbol.Index = null,
|
||||
got_index: ?Symbol.Index = null,
|
||||
plt_index: ?Symbol.Index = null,
|
||||
end_index: ?Symbol.Index = null,
|
||||
gnu_eh_frame_hdr_index: ?Symbol.Index = null,
|
||||
dso_handle_index: ?Symbol.Index = null,
|
||||
rela_iplt_start_index: ?Symbol.Index = null,
|
||||
rela_iplt_end_index: ?Symbol.Index = null,
|
||||
global_pointer_index: ?Symbol.Index = null,
|
||||
start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
|
||||
|
||||
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||
|
||||
pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
|
||||
self.symtab.deinit(allocator);
|
||||
self.strtab.deinit(allocator);
|
||||
self.symbols.deinit(allocator);
|
||||
self.start_stop_indexes.deinit(allocator);
|
||||
}
|
||||
|
||||
pub fn addGlobal(self: *LinkerDefined, name: [:0]const u8, elf_file: *Elf) !u32 {
|
||||
pub fn init(self: *LinkerDefined, allocator: Allocator) !void {
|
||||
// Null byte in strtab
|
||||
try self.strtab.append(allocator, 0);
|
||||
}
|
||||
|
||||
pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
|
||||
if (elf_file.entry_name) |name| {
|
||||
self.entry_index = try self.addGlobal(name, elf_file);
|
||||
}
|
||||
|
||||
self.dynamic_index = try self.addGlobal("_DYNAMIC", elf_file);
|
||||
self.ehdr_start_index = try self.addGlobal("__ehdr_start", elf_file);
|
||||
self.init_array_start_index = try self.addGlobal("__init_array_start", elf_file);
|
||||
self.init_array_end_index = try self.addGlobal("__init_array_end", elf_file);
|
||||
self.fini_array_start_index = try self.addGlobal("__fini_array_start", elf_file);
|
||||
self.fini_array_end_index = try self.addGlobal("__fini_array_end", elf_file);
|
||||
self.preinit_array_start_index = try self.addGlobal("__preinit_array_start", elf_file);
|
||||
self.preinit_array_end_index = try self.addGlobal("__preinit_array_end", elf_file);
|
||||
self.got_index = try self.addGlobal("_GLOBAL_OFFSET_TABLE_", elf_file);
|
||||
self.plt_index = try self.addGlobal("_PROCEDURE_LINKAGE_TABLE_", elf_file);
|
||||
self.end_index = try self.addGlobal("_end", elf_file);
|
||||
|
||||
if (elf_file.base.comp.link_eh_frame_hdr) {
|
||||
self.gnu_eh_frame_hdr_index = try self.addGlobal("__GNU_EH_FRAME_HDR", elf_file);
|
||||
}
|
||||
|
||||
self.dso_handle_index = try self.addGlobal("__dso_handle", elf_file);
|
||||
self.rela_iplt_start_index = try self.addGlobal("__rela_iplt_start", elf_file);
|
||||
self.rela_iplt_end_index = try self.addGlobal("__rela_iplt_end", elf_file);
|
||||
|
||||
for (elf_file.shdrs.items) |shdr| {
|
||||
if (elf_file.getStartStopBasename(shdr)) |name| {
|
||||
try self.start_stop_indexes.ensureUnusedCapacity(gpa, 2);
|
||||
|
||||
const start = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
|
||||
defer gpa.free(start);
|
||||
const stop = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
|
||||
defer gpa.free(stop);
|
||||
|
||||
self.start_stop_indexes.appendAssumeCapacity(try self.addGlobal(start, elf_file));
|
||||
self.start_stop_indexes.appendAssumeCapacity(try self.addGlobal(stop, elf_file));
|
||||
}
|
||||
}
|
||||
|
||||
if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) {
|
||||
self.global_pointer_index = try self.addGlobal("__global_pointer$", elf_file);
|
||||
}
|
||||
}
|
||||
|
||||
fn addGlobal(self: *LinkerDefined, name: []const u8, elf_file: *Elf) !u32 {
|
||||
const comp = elf_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
try self.symtab.ensureUnusedCapacity(gpa, 1);
|
||||
@@ -41,7 +113,7 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
|
||||
const global = elf_file.symbol(index);
|
||||
if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
|
||||
global.value = 0;
|
||||
global.atom_index = 0;
|
||||
global.ref = .{ .index = 0, .file = 0 };
|
||||
global.file_index = self.index;
|
||||
global.esym_index = sym_idx;
|
||||
global.version_index = elf_file.default_sym_version;
|
||||
@@ -49,6 +121,154 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {
|
||||
const comp = elf_file.base.comp;
|
||||
const link_mode = comp.config.link_mode;
|
||||
|
||||
// _DYNAMIC
|
||||
if (elf_file.dynamic_section_index) |shndx| {
|
||||
const shdr = &elf_file.shdrs.items[shndx];
|
||||
const symbol_ptr = elf_file.symbol(self.dynamic_index.?);
|
||||
symbol_ptr.value = @intCast(shdr.sh_addr);
|
||||
symbol_ptr.output_section_index = shndx;
|
||||
}
|
||||
|
||||
// __ehdr_start
|
||||
{
|
||||
const symbol_ptr = elf_file.symbol(self.ehdr_start_index.?);
|
||||
symbol_ptr.value = @intCast(elf_file.image_base);
|
||||
symbol_ptr.output_section_index = 1;
|
||||
}
|
||||
|
||||
// __init_array_start, __init_array_end
|
||||
if (elf_file.sectionByName(".init_array")) |shndx| {
|
||||
const start_sym = elf_file.symbol(self.init_array_start_index.?);
|
||||
const end_sym = elf_file.symbol(self.init_array_end_index.?);
|
||||
const shdr = &elf_file.shdrs.items[shndx];
|
||||
start_sym.output_section_index = shndx;
|
||||
start_sym.value = @intCast(shdr.sh_addr);
|
||||
end_sym.output_section_index = shndx;
|
||||
end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
|
||||
}
|
||||
|
||||
// __fini_array_start, __fini_array_end
|
||||
if (elf_file.sectionByName(".fini_array")) |shndx| {
|
||||
const start_sym = elf_file.symbol(self.fini_array_start_index.?);
|
||||
const end_sym = elf_file.symbol(self.fini_array_end_index.?);
|
||||
const shdr = &elf_file.shdrs.items[shndx];
|
||||
start_sym.output_section_index = shndx;
|
||||
start_sym.value = @intCast(shdr.sh_addr);
|
||||
end_sym.output_section_index = shndx;
|
||||
end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
|
||||
}
|
||||
|
||||
// __preinit_array_start, __preinit_array_end
|
||||
if (elf_file.sectionByName(".preinit_array")) |shndx| {
|
||||
const start_sym = elf_file.symbol(self.preinit_array_start_index.?);
|
||||
const end_sym = elf_file.symbol(self.preinit_array_end_index.?);
|
||||
const shdr = &elf_file.shdrs.items[shndx];
|
||||
start_sym.output_section_index = shndx;
|
||||
start_sym.value = @intCast(shdr.sh_addr);
|
||||
end_sym.output_section_index = shndx;
|
||||
end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
|
||||
}
|
||||
|
||||
// _GLOBAL_OFFSET_TABLE_
|
||||
if (elf_file.getTarget().cpu.arch == .x86_64) {
|
||||
if (elf_file.got_plt_section_index) |shndx| {
|
||||
const shdr = elf_file.shdrs.items[shndx];
|
||||
const sym = elf_file.symbol(self.got_index.?);
|
||||
sym.value = @intCast(shdr.sh_addr);
|
||||
sym.output_section_index = shndx;
|
||||
}
|
||||
} else {
|
||||
if (elf_file.got_section_index) |shndx| {
|
||||
const shdr = elf_file.shdrs.items[shndx];
|
||||
const sym = elf_file.symbol(self.got_index.?);
|
||||
sym.value = @intCast(shdr.sh_addr);
|
||||
sym.output_section_index = shndx;
|
||||
}
|
||||
}
|
||||
|
||||
// _PROCEDURE_LINKAGE_TABLE_
|
||||
if (elf_file.plt_section_index) |shndx| {
|
||||
const shdr = &elf_file.shdrs.items[shndx];
|
||||
const symbol_ptr = elf_file.symbol(self.plt_index.?);
|
||||
symbol_ptr.value = @intCast(shdr.sh_addr);
|
||||
symbol_ptr.output_section_index = shndx;
|
||||
}
|
||||
|
||||
// __dso_handle
|
||||
if (self.dso_handle_index) |index| {
|
||||
const shdr = &elf_file.shdrs.items[1];
|
||||
const symbol_ptr = elf_file.symbol(index);
|
||||
symbol_ptr.value = @intCast(shdr.sh_addr);
|
||||
symbol_ptr.output_section_index = 0;
|
||||
}
|
||||
|
||||
// __GNU_EH_FRAME_HDR
|
||||
if (elf_file.eh_frame_hdr_section_index) |shndx| {
|
||||
const shdr = &elf_file.shdrs.items[shndx];
|
||||
const symbol_ptr = elf_file.symbol(self.gnu_eh_frame_hdr_index.?);
|
||||
symbol_ptr.value = @intCast(shdr.sh_addr);
|
||||
symbol_ptr.output_section_index = shndx;
|
||||
}
|
||||
|
||||
// __rela_iplt_start, __rela_iplt_end
|
||||
if (elf_file.rela_dyn_section_index) |shndx| blk: {
|
||||
if (link_mode != .static or comp.config.pie) break :blk;
|
||||
const shdr = &elf_file.shdrs.items[shndx];
|
||||
const end_addr = shdr.sh_addr + shdr.sh_size;
|
||||
const start_addr = end_addr - elf_file.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
|
||||
const start_sym = elf_file.symbol(self.rela_iplt_start_index.?);
|
||||
const end_sym = elf_file.symbol(self.rela_iplt_end_index.?);
|
||||
start_sym.value = @intCast(start_addr);
|
||||
start_sym.output_section_index = shndx;
|
||||
end_sym.value = @intCast(end_addr);
|
||||
end_sym.output_section_index = shndx;
|
||||
}
|
||||
|
||||
// _end
|
||||
{
|
||||
const end_symbol = elf_file.symbol(self.end_index.?);
|
||||
for (elf_file.shdrs.items, 0..) |shdr, shndx| {
|
||||
if (shdr.sh_flags & elf.SHF_ALLOC != 0) {
|
||||
end_symbol.value = @intCast(shdr.sh_addr + shdr.sh_size);
|
||||
end_symbol.output_section_index = @intCast(shndx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// __start_*, __stop_*
|
||||
{
|
||||
var index: usize = 0;
|
||||
while (index < self.start_stop_indexes.items.len) : (index += 2) {
|
||||
const start = elf_file.symbol(self.start_stop_indexes.items[index]);
|
||||
const name = start.name(elf_file);
|
||||
const stop = elf_file.symbol(self.start_stop_indexes.items[index + 1]);
|
||||
const shndx = elf_file.sectionByName(name["__start_".len..]).?;
|
||||
const shdr = &elf_file.shdrs.items[shndx];
|
||||
start.value = @intCast(shdr.sh_addr);
|
||||
start.output_section_index = shndx;
|
||||
stop.value = @intCast(shdr.sh_addr + shdr.sh_size);
|
||||
stop.output_section_index = shndx;
|
||||
}
|
||||
}
|
||||
|
||||
// __global_pointer$
|
||||
if (self.global_pointer_index) |index| {
|
||||
const sym = elf_file.symbol(index);
|
||||
if (elf_file.sectionByName(".sdata")) |shndx| {
|
||||
const shdr = elf_file.shdrs.items[shndx];
|
||||
sym.value = @intCast(shdr.sh_addr + 0x800);
|
||||
sym.output_section_index = shndx;
|
||||
} else {
|
||||
sym.value = 0;
|
||||
sym.output_section_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn globals(self: LinkerDefined) []const Symbol.Index {
|
||||
return self.symbols.items;
|
||||
}
|
||||
@@ -127,6 +347,7 @@ const mem = std.mem;
|
||||
const std = @import("std");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Atom = @import("Atom.zig");
|
||||
const Elf = @import("../Elf.zig");
|
||||
const File = @import("file.zig").File;
|
||||
const LinkerDefined = @This();
|
||||
|
||||
@@ -10,12 +10,17 @@ symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
first_global: ?Symbol.Index = null,
|
||||
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
|
||||
comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{},
|
||||
comdat_group_data: std.ArrayListUnmanaged(u32) = .{},
|
||||
relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
|
||||
|
||||
merge_sections: std.ArrayListUnmanaged(InputMergeSection.Index) = .{},
|
||||
atoms: std.ArrayListUnmanaged(Atom) = .{},
|
||||
atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
|
||||
atoms_extra: std.ArrayListUnmanaged(u32) = .{},
|
||||
|
||||
comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .{},
|
||||
comdat_group_data: std.ArrayListUnmanaged(u32) = .{},
|
||||
|
||||
input_merge_sections: std.ArrayListUnmanaged(InputMergeSection) = .{},
|
||||
input_merge_sections_indexes: std.ArrayListUnmanaged(InputMergeSection.Index) = .{},
|
||||
|
||||
fdes: std.ArrayListUnmanaged(Fde) = .{},
|
||||
cies: std.ArrayListUnmanaged(Cie) = .{},
|
||||
@@ -47,13 +52,19 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
|
||||
self.strtab.deinit(allocator);
|
||||
self.symbols.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);
|
||||
self.merge_sections.deinit(allocator);
|
||||
for (self.input_merge_sections.items) |*isec| {
|
||||
isec.deinit(allocator);
|
||||
}
|
||||
self.input_merge_sections.deinit(allocator);
|
||||
self.input_merge_sections_indexes.deinit(allocator);
|
||||
}
|
||||
|
||||
pub fn parse(self: *Object, elf_file: *Elf) !void {
|
||||
@@ -62,14 +73,20 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
|
||||
const handle = elf_file.fileHandle(self.file_handle);
|
||||
|
||||
try self.parseCommon(gpa, handle, elf_file);
|
||||
|
||||
// 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.initSymtab(gpa, elf_file);
|
||||
|
||||
for (self.shdrs.items, 0..) |shdr, i| {
|
||||
const atom = elf_file.atom(self.atoms.items[i]) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
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.name(elf_file), ".eh_frame"))
|
||||
mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame"))
|
||||
{
|
||||
try self.parseEhFrame(gpa, handle, @as(u32, @intCast(i)), elf_file);
|
||||
}
|
||||
@@ -169,8 +186,11 @@ 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 shdrs = self.shdrs.items;
|
||||
try self.atoms.resize(allocator, shdrs.len);
|
||||
@memset(self.atoms.items, 0);
|
||||
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);
|
||||
@memset(self.atoms_indexes.items, 0);
|
||||
|
||||
for (shdrs, 0..) |shdr, i| {
|
||||
if (shdr.sh_flags & elf.SHF_EXCLUDE != 0 and
|
||||
@@ -188,37 +208,53 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
|
||||
const group_signature = blk: {
|
||||
if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) {
|
||||
const sym_shdr = shdrs[group_info_sym.st_shndx];
|
||||
break :blk self.getString(sym_shdr.sh_name);
|
||||
break :blk sym_shdr.sh_name;
|
||||
}
|
||||
break :blk self.getString(group_info_sym.st_name);
|
||||
break :blk group_info_sym.st_name;
|
||||
};
|
||||
|
||||
const shndx = @as(u32, @intCast(i));
|
||||
const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
|
||||
defer allocator.free(group_raw_data);
|
||||
const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));
|
||||
const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch {
|
||||
try elf_file.reportParseError2(
|
||||
self.index,
|
||||
"corrupt section group: not evenly divisible ",
|
||||
.{},
|
||||
);
|
||||
return error.MalformedObject;
|
||||
};
|
||||
if (group_nmembers == 0) {
|
||||
try elf_file.reportParseError2(
|
||||
self.index,
|
||||
"corrupt section group: empty section",
|
||||
.{},
|
||||
);
|
||||
return error.MalformedObject;
|
||||
}
|
||||
const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
|
||||
|
||||
if (group_members[0] != elf.GRP_COMDAT) {
|
||||
// TODO convert into an error
|
||||
log.debug("{}: unknown SHT_GROUP format", .{self.fmtPath()});
|
||||
continue;
|
||||
try elf_file.reportParseError2(
|
||||
self.index,
|
||||
"corrupt section group: unknown SHT_GROUP format",
|
||||
.{},
|
||||
);
|
||||
return error.MalformedObject;
|
||||
}
|
||||
|
||||
const group_start = @as(u32, @intCast(self.comdat_group_data.items.len));
|
||||
try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]);
|
||||
|
||||
const gop = try elf_file.getOrCreateComdatGroupOwner(group_signature);
|
||||
const comdat_group_index = try elf_file.addComdatGroup();
|
||||
const comdat_group = elf_file.comdatGroup(comdat_group_index);
|
||||
const comdat_group_index = try self.addComdatGroup(allocator);
|
||||
const comdat_group = self.comdatGroup(comdat_group_index);
|
||||
comdat_group.* = .{
|
||||
.owner = gop.index,
|
||||
.file = self.index,
|
||||
.signature_off = group_signature,
|
||||
.file_index = self.index,
|
||||
.shndx = shndx,
|
||||
.members_start = group_start,
|
||||
.members_len = @intCast(group_nmembers - 1),
|
||||
};
|
||||
try self.comdat_groups.append(allocator, comdat_group_index);
|
||||
},
|
||||
|
||||
elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"),
|
||||
@@ -233,7 +269,19 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
|
||||
else => {
|
||||
const shndx = @as(u32, @intCast(i));
|
||||
if (self.skipShdr(shndx, elf_file)) continue;
|
||||
try self.addAtom(allocator, handle, shdr, shndx, elf_file);
|
||||
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 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) };
|
||||
const atom_index = self.addAtomAssumeCapacity(.{
|
||||
.name = shdr.sh_name,
|
||||
.shndx = shndx,
|
||||
.size = size,
|
||||
.alignment = alignment,
|
||||
});
|
||||
self.atoms_indexes.items[shndx] = atom_index;
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -241,14 +289,14 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
|
||||
// Parse relocs sections if any.
|
||||
for (shdrs, 0..) |shdr, i| switch (shdr.sh_type) {
|
||||
elf.SHT_REL, elf.SHT_RELA => {
|
||||
const atom_index = self.atoms.items[shdr.sh_info];
|
||||
if (elf_file.atom(atom_index)) |atom| {
|
||||
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);
|
||||
atom.relocs_section_index = @intCast(i);
|
||||
atom_ptr.relocs_section_index = @intCast(i);
|
||||
const rel_index: u32 = @intCast(self.relocs.items.len);
|
||||
const rel_count: u32 = @intCast(relocs.len);
|
||||
try atom.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, elf_file);
|
||||
atom_ptr.addExtra(.{ .rel_index = rel_index, .rel_count = rel_count }, elf_file);
|
||||
try self.relocs.appendUnalignedSlice(allocator, relocs);
|
||||
if (elf_file.getTarget().cpu.arch == .riscv64) {
|
||||
sortRelocs(self.relocs.items[rel_index..][0..rel_count]);
|
||||
@@ -259,27 +307,6 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
|
||||
};
|
||||
}
|
||||
|
||||
fn addAtom(self: *Object, allocator: Allocator, handle: std.fs.File, shdr: elf.Elf64_Shdr, shndx: u32, elf_file: *Elf) !void {
|
||||
const atom_index = try elf_file.addAtom();
|
||||
const atom = elf_file.atom(atom_index).?;
|
||||
atom.atom_index = atom_index;
|
||||
atom.name_offset = shdr.sh_name;
|
||||
atom.file_index = self.index;
|
||||
atom.input_section_index = shndx;
|
||||
self.atoms.items[shndx] = atom_index;
|
||||
|
||||
if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) {
|
||||
const data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
|
||||
defer allocator.free(data);
|
||||
const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*;
|
||||
atom.size = chdr.ch_size;
|
||||
atom.alignment = Alignment.fromNonzeroByteUnits(chdr.ch_addralign);
|
||||
} else {
|
||||
atom.size = shdr.sh_size;
|
||||
atom.alignment = Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
|
||||
}
|
||||
}
|
||||
|
||||
fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u32 {
|
||||
const name = blk: {
|
||||
const name = self.getString(shdr.sh_name);
|
||||
@@ -327,7 +354,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{O
|
||||
const out_shndx = elf_file.sectionByName(name) orelse try elf_file.addSection(.{
|
||||
.type = @"type",
|
||||
.flags = flags,
|
||||
.name = name,
|
||||
.name = try elf_file.insertShString(name),
|
||||
});
|
||||
return out_shndx;
|
||||
}
|
||||
@@ -359,8 +386,10 @@ fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
|
||||
sym_ptr.value = @intCast(sym.st_value);
|
||||
sym_ptr.name_offset = sym.st_name;
|
||||
sym_ptr.esym_index = @as(u32, @intCast(i));
|
||||
sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];
|
||||
sym_ptr.file_index = self.index;
|
||||
if (sym.st_shndx != elf.SHN_ABS) {
|
||||
sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index };
|
||||
}
|
||||
}
|
||||
|
||||
for (self.symtab.items[first_global..]) |sym| {
|
||||
@@ -447,15 +476,14 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx:
|
||||
var i: u32 = @as(u32, @intCast(fdes_start));
|
||||
while (i < self.fdes.items.len) {
|
||||
const fde = self.fdes.items[i];
|
||||
const atom = fde.atom(elf_file);
|
||||
const atom_ptr = fde.atom(elf_file);
|
||||
const start = i;
|
||||
i += 1;
|
||||
while (i < self.fdes.items.len) : (i += 1) {
|
||||
const next_fde = self.fdes.items[i];
|
||||
if (atom.atom_index != next_fde.atom(elf_file).atom_index) break;
|
||||
if (atom_ptr.atom_index != next_fde.atom(elf_file).atom_index) break;
|
||||
}
|
||||
try atom.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);
|
||||
atom.flags.fde = true;
|
||||
atom_ptr.addExtra(.{ .fde_start = start, .fde_count = i - start }, elf_file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,19 +526,19 @@ fn filterRelocs(
|
||||
pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
|
||||
const comp = elf_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
for (self.atoms.items) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const shdr = atom.inputShdr(elf_file);
|
||||
for (self.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
const shdr = atom_ptr.inputShdr(elf_file);
|
||||
if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
|
||||
if (shdr.sh_type == elf.SHT_NOBITS) continue;
|
||||
if (atom.scanRelocsRequiresCode(elf_file)) {
|
||||
if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
|
||||
// TODO ideally, we don't have to decompress at this stage (should already be done)
|
||||
// and we just fetch the code slice.
|
||||
const code = try self.codeDecompressAlloc(elf_file, atom_index);
|
||||
defer gpa.free(code);
|
||||
try atom.scanRelocs(elf_file, code, undefs);
|
||||
} else try atom.scanRelocs(elf_file, null, undefs);
|
||||
try atom_ptr.scanRelocs(elf_file, code, undefs);
|
||||
} else try atom_ptr.scanRelocs(elf_file, null, undefs);
|
||||
}
|
||||
|
||||
for (self.cies.items) |cie| {
|
||||
@@ -538,19 +566,21 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
|
||||
if (esym.st_shndx == elf.SHN_UNDEF) continue;
|
||||
|
||||
if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
|
||||
const atom_index = self.atoms.items[esym.st_shndx];
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const atom_index = self.atoms_indexes.items[esym.st_shndx];
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
}
|
||||
|
||||
const global = elf_file.symbol(index);
|
||||
if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) {
|
||||
const atom_index = switch (esym.st_shndx) {
|
||||
elf.SHN_ABS, elf.SHN_COMMON => 0,
|
||||
else => self.atoms.items[esym.st_shndx],
|
||||
};
|
||||
switch (esym.st_shndx) {
|
||||
elf.SHN_ABS, elf.SHN_COMMON => {},
|
||||
else => global.ref = .{
|
||||
.index = self.atoms_indexes.items[esym.st_shndx],
|
||||
.file = self.index,
|
||||
},
|
||||
}
|
||||
global.value = @intCast(esym.st_value);
|
||||
global.atom_index = atom_index;
|
||||
global.esym_index = esym_index;
|
||||
global.file_index = self.index;
|
||||
global.version_index = elf_file.default_sym_version;
|
||||
@@ -579,7 +609,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
|
||||
};
|
||||
|
||||
global.value = 0;
|
||||
global.atom_index = 0;
|
||||
global.ref = .{ .index = 0, .file = 0 };
|
||||
global.esym_index = esym_index;
|
||||
global.file_index = self.index;
|
||||
global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
|
||||
@@ -600,7 +630,7 @@ pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
|
||||
}
|
||||
|
||||
global.value = 0;
|
||||
global.atom_index = 0;
|
||||
global.ref = .{ .index = 0, .file = 0 };
|
||||
global.esym_index = esym_index;
|
||||
global.file_index = self.index;
|
||||
}
|
||||
@@ -624,13 +654,13 @@ pub fn markLive(self: *Object, elf_file: *Elf) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn markEhFrameAtomsDead(self: Object, elf_file: *Elf) void {
|
||||
pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {
|
||||
const cpu_arch = elf_file.getTarget().cpu.arch;
|
||||
for (self.atoms.items) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
const is_eh_frame = (cpu_arch == .x86_64 and atom.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND) or
|
||||
mem.eql(u8, atom.name(elf_file), ".eh_frame");
|
||||
if (atom.flags.alive and is_eh_frame) atom.flags.alive = false;
|
||||
for (self.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
const is_eh_frame = (cpu_arch == .x86_64 and atom_ptr.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND) or
|
||||
mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame");
|
||||
if (atom_ptr.alive and is_eh_frame) atom_ptr.alive = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -648,9 +678,9 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO
|
||||
sym.st_shndx == elf.SHN_COMMON) continue;
|
||||
|
||||
if (sym.st_shndx != elf.SHN_ABS) {
|
||||
const atom_index = self.atoms.items[sym.st_shndx];
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const atom_index = self.atoms_indexes.items[sym.st_shndx];
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
}
|
||||
|
||||
const gop = try dupes.getOrPut(index);
|
||||
@@ -661,25 +691,24 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initMergeSections(self: *Object, elf_file: *Elf) !void {
|
||||
pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
|
||||
try self.merge_sections.resize(gpa, self.shdrs.items.len);
|
||||
@memset(self.merge_sections.items, 0);
|
||||
try self.input_merge_sections.ensureUnusedCapacity(gpa, self.shdrs.items.len);
|
||||
try self.input_merge_sections_indexes.resize(gpa, self.shdrs.items.len);
|
||||
@memset(self.input_merge_sections_indexes.items, 0);
|
||||
|
||||
for (self.shdrs.items, 0..) |shdr, shndx| {
|
||||
if (shdr.sh_flags & elf.SHF_MERGE == 0) continue;
|
||||
|
||||
const atom_index = self.atoms.items[shndx];
|
||||
const atom_ptr = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.flags.alive) continue;
|
||||
const atom_index = self.atoms_indexes.items[shndx];
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
if (atom_ptr.relocs(elf_file).len > 0) continue;
|
||||
|
||||
const imsec_idx = try elf_file.addInputMergeSection();
|
||||
const imsec = elf_file.inputMergeSection(imsec_idx).?;
|
||||
self.merge_sections.items[shndx] = imsec_idx;
|
||||
|
||||
imsec.merge_section_index = try elf_file.getOrCreateMergeSection(atom_ptr.name(elf_file), shdr.sh_flags, shdr.sh_type);
|
||||
const imsec_idx = try self.addInputMergeSection(gpa);
|
||||
const imsec = self.inputMergeSection(imsec_idx).?;
|
||||
self.input_merge_sections_indexes.items[shndx] = imsec_idx;
|
||||
imsec.atom_index = atom_index;
|
||||
|
||||
const data = try self.codeDecompressAlloc(elf_file, atom_index);
|
||||
@@ -734,18 +763,31 @@ pub fn initMergeSections(self: *Object, elf_file: *Elf) !void {
|
||||
}
|
||||
}
|
||||
|
||||
atom_ptr.flags.alive = false;
|
||||
atom_ptr.alive = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initOutputMergeSections(self: *Object, elf_file: *Elf) !void {
|
||||
for (self.input_merge_sections_indexes.items) |index| {
|
||||
const imsec = self.inputMergeSection(index) orelse continue;
|
||||
const atom_ptr = self.atom(imsec.atom_index).?;
|
||||
const shdr = atom_ptr.inputShdr(elf_file);
|
||||
imsec.merge_section_index = try elf_file.getOrCreateMergeSection(
|
||||
atom_ptr.name(elf_file),
|
||||
shdr.sh_flags,
|
||||
shdr.sh_type,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
|
||||
for (self.merge_sections.items) |index| {
|
||||
const imsec = elf_file.inputMergeSection(index) orelse continue;
|
||||
for (self.input_merge_sections_indexes.items) |index| {
|
||||
const imsec = self.inputMergeSection(index) orelse continue;
|
||||
if (imsec.offsets.items.len == 0) continue;
|
||||
const msec = elf_file.mergeSection(imsec.merge_section_index);
|
||||
const atom_ptr = elf_file.atom(imsec.atom_index).?;
|
||||
const atom_ptr = self.atom(imsec.atom_index).?;
|
||||
const isec = atom_ptr.inputShdr(elf_file);
|
||||
|
||||
try imsec.subsections.resize(gpa, imsec.strings.items.len);
|
||||
@@ -754,8 +796,8 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
|
||||
const string = imsec.bytes.items[str.pos..][0..str.len];
|
||||
const res = try msec.insert(gpa, string);
|
||||
if (!res.found_existing) {
|
||||
const msub_index = try elf_file.addMergeSubsection();
|
||||
const msub = elf_file.mergeSubsection(msub_index);
|
||||
const msub_index = try msec.addMergeSubsection(gpa);
|
||||
const msub = msec.mergeSubsection(msub_index);
|
||||
msub.merge_section_index = imsec.merge_section_index;
|
||||
msub.string_index = res.key.pos;
|
||||
msub.alignment = atom_ptr.alignment;
|
||||
@@ -776,10 +818,10 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
|
||||
|
||||
if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue;
|
||||
|
||||
const imsec_index = self.merge_sections.items[esym.st_shndx];
|
||||
const imsec = elf_file.inputMergeSection(imsec_index) orelse continue;
|
||||
const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx];
|
||||
const imsec = self.inputMergeSection(imsec_index) orelse continue;
|
||||
if (imsec.offsets.items.len == 0) continue;
|
||||
const msub_index, const offset = imsec.findSubsection(@intCast(esym.st_value)) orelse {
|
||||
const res = imsec.findSubsection(@intCast(esym.st_value)) orelse {
|
||||
var err = try elf_file.base.addErrorWithNotes(2);
|
||||
try err.addMsg("invalid symbol value: {x}", .{esym.st_value});
|
||||
try err.addNote("for symbol {s}", .{sym.name(elf_file)});
|
||||
@@ -787,45 +829,44 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
|
||||
return error.MalformedObject;
|
||||
};
|
||||
|
||||
try sym.addExtra(.{ .subsection = msub_index }, elf_file);
|
||||
sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };
|
||||
sym.flags.merge_subsection = true;
|
||||
sym.value = offset;
|
||||
sym.value = res.offset;
|
||||
}
|
||||
|
||||
for (self.atoms.items) |atom_index| {
|
||||
const atom_ptr = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.flags.alive) continue;
|
||||
const extras = atom_ptr.extra(elf_file) orelse continue;
|
||||
for (self.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
const extras = atom_ptr.extra(elf_file);
|
||||
const relocs = self.relocs.items[extras.rel_index..][0..extras.rel_count];
|
||||
for (relocs) |*rel| {
|
||||
const esym = self.symtab.items[rel.r_sym()];
|
||||
if (esym.st_type() != elf.STT_SECTION) continue;
|
||||
|
||||
const imsec_index = self.merge_sections.items[esym.st_shndx];
|
||||
const imsec = elf_file.inputMergeSection(imsec_index) orelse continue;
|
||||
const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx];
|
||||
const imsec = self.inputMergeSection(imsec_index) orelse continue;
|
||||
if (imsec.offsets.items.len == 0) continue;
|
||||
const msub_index, const offset = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {
|
||||
const msec = elf_file.mergeSection(imsec.merge_section_index);
|
||||
const res = imsec.findSubsection(@intCast(@as(i64, @intCast(esym.st_value)) + rel.r_addend)) orelse {
|
||||
var err = try elf_file.base.addErrorWithNotes(1);
|
||||
try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});
|
||||
try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
|
||||
return error.MalformedObject;
|
||||
};
|
||||
const msub = elf_file.mergeSubsection(msub_index);
|
||||
const msec = msub.mergeSection(elf_file);
|
||||
|
||||
const out_sym_idx: u64 = @intCast(self.symbols.items.len);
|
||||
try self.symbols.ensureUnusedCapacity(gpa, 1);
|
||||
const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), msub_index });
|
||||
const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), res.msub_index });
|
||||
defer gpa.free(name);
|
||||
const sym_index = try elf_file.addSymbol();
|
||||
const sym = elf_file.symbol(sym_index);
|
||||
sym.* = .{
|
||||
.value = @bitCast(@as(i64, @intCast(offset)) - rel.r_addend),
|
||||
.value = @bitCast(@as(i64, @intCast(res.offset)) - rel.r_addend),
|
||||
.name_offset = try self.addString(gpa, name),
|
||||
.esym_index = rel.r_sym(),
|
||||
.file_index = self.index,
|
||||
};
|
||||
try sym.addExtra(.{ .subsection = msub_index }, elf_file);
|
||||
sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };
|
||||
sym.flags.merge_subsection = true;
|
||||
self.symbols.addOneAssumeCapacity().* = sym_index;
|
||||
rel.r_info = (out_sym_idx << 32) | rel.r_type();
|
||||
@@ -857,21 +898,10 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
|
||||
const comp = elf_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
|
||||
const atom_index = try elf_file.addAtom();
|
||||
try self.atoms.append(gpa, atom_index);
|
||||
|
||||
const is_tls = global.type(elf_file) == elf.STT_TLS;
|
||||
const name = if (is_tls) ".tls_common" else ".common";
|
||||
|
||||
const atom = elf_file.atom(atom_index).?;
|
||||
const name_offset = @as(u32, @intCast(self.strtab.items.len));
|
||||
try self.strtab.writer(gpa).print("{s}\x00", .{name});
|
||||
atom.atom_index = atom_index;
|
||||
atom.name_offset = name_offset;
|
||||
atom.file_index = self.index;
|
||||
atom.size = this_sym.st_size;
|
||||
const alignment = this_sym.st_value;
|
||||
atom.alignment = Alignment.fromNonzeroByteUnits(alignment);
|
||||
|
||||
var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;
|
||||
if (is_tls) sh_flags |= elf.SHF_TLS;
|
||||
@@ -887,78 +917,84 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
|
||||
.sh_size = sh_size,
|
||||
.sh_link = 0,
|
||||
.sh_info = 0,
|
||||
.sh_addralign = alignment,
|
||||
.sh_addralign = this_sym.st_value,
|
||||
.sh_entsize = 0,
|
||||
};
|
||||
atom.input_section_index = shndx;
|
||||
|
||||
const atom_index = try self.addAtom(gpa, .{
|
||||
.name = name_offset,
|
||||
.shndx = shndx,
|
||||
.size = this_sym.st_size,
|
||||
.alignment = Alignment.fromNonzeroByteUnits(this_sym.st_value),
|
||||
});
|
||||
try self.atoms_indexes.append(gpa, atom_index);
|
||||
|
||||
global.value = 0;
|
||||
global.atom_index = atom_index;
|
||||
global.ref = .{ .index = atom_index, .file = self.index };
|
||||
global.flags.weak = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initOutputSections(self: Object, elf_file: *Elf) !void {
|
||||
for (self.atoms.items) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const shdr = atom.inputShdr(elf_file);
|
||||
pub fn resolveComdatGroups(self: *Object, elf_file: *Elf, table: anytype) !void {
|
||||
for (self.comdat_groups.items, 0..) |*cg, cgi| {
|
||||
const signature = cg.signature(elf_file);
|
||||
const gop = try table.getOrPut(signature);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{ .index = @intCast(cgi), .file = self.index };
|
||||
continue;
|
||||
}
|
||||
const current = elf_file.comdatGroup(gop.value_ptr.*);
|
||||
cg.alive = false;
|
||||
if (self.index < current.file_index) {
|
||||
current.alive = false;
|
||||
cg.alive = true;
|
||||
gop.value_ptr.* = .{ .index = @intCast(cgi), .file = self.index };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn markComdatGroupsDead(self: *Object, elf_file: *Elf) void {
|
||||
for (self.comdat_groups.items) |cg| {
|
||||
if (cg.alive) continue;
|
||||
for (cg.comdatGroupMembers(elf_file)) |shndx| {
|
||||
const atom_index = self.atoms_indexes.items[shndx];
|
||||
if (self.atom(atom_index)) |atom_ptr| {
|
||||
atom_ptr.alive = false;
|
||||
atom_ptr.markFdesDead(elf_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
|
||||
for (self.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
const shdr = atom_ptr.inputShdr(elf_file);
|
||||
_ = try self.initOutputSection(elf_file, shdr);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
|
||||
for (self.atoms.items) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const shdr = atom.inputShdr(elf_file);
|
||||
atom.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
|
||||
for (self.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
const shdr = atom_ptr.inputShdr(elf_file);
|
||||
atom_ptr.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
|
||||
|
||||
const comp = elf_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
const gop = try elf_file.output_sections.getOrPut(gpa, atom.output_section_index);
|
||||
const gop = try elf_file.output_sections.getOrPut(gpa, atom_ptr.output_section_index);
|
||||
if (!gop.found_existing) gop.value_ptr.* = .{};
|
||||
try gop.value_ptr.append(gpa, atom_index);
|
||||
}
|
||||
|
||||
for (self.locals()) |local_index| {
|
||||
const local = elf_file.symbol(local_index);
|
||||
if (local.mergeSubsection(elf_file)) |msub| {
|
||||
if (!msub.alive) continue;
|
||||
local.output_section_index = msub.mergeSection(elf_file).output_section_index;
|
||||
continue;
|
||||
}
|
||||
const atom = local.atom(elf_file) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
local.output_section_index = atom.output_section_index;
|
||||
}
|
||||
|
||||
for (self.globals()) |global_index| {
|
||||
const global = elf_file.symbol(global_index);
|
||||
if (global.file(elf_file).?.index() != self.index) continue;
|
||||
if (global.mergeSubsection(elf_file)) |msub| {
|
||||
if (!msub.alive) continue;
|
||||
global.output_section_index = msub.mergeSection(elf_file).output_section_index;
|
||||
continue;
|
||||
}
|
||||
const atom = global.atom(elf_file) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
global.output_section_index = atom.output_section_index;
|
||||
}
|
||||
|
||||
for (self.symbols.items[self.symtab.items.len..]) |local_index| {
|
||||
const local = elf_file.symbol(local_index);
|
||||
const msub = local.mergeSubsection(elf_file).?;
|
||||
if (!msub.alive) continue;
|
||||
local.output_section_index = msub.mergeSection(elf_file).output_section_index;
|
||||
try gop.value_ptr.append(gpa, .{ .index = atom_index, .file = self.index });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
|
||||
for (self.atoms.items) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const shndx = atom.relocsShndx() orelse continue;
|
||||
pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {
|
||||
for (self.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
const shndx = atom_ptr.relocsShndx() orelse continue;
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
const out_shndx = try self.initOutputSection(elf_file, shdr);
|
||||
const out_shdr = &elf_file.shdrs.items[out_shndx];
|
||||
@@ -968,24 +1004,24 @@ pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void {
|
||||
for (self.atoms.items) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void {
|
||||
for (self.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
const shndx = blk: {
|
||||
const shndx = atom.relocsShndx() orelse continue;
|
||||
const shndx = atom_ptr.relocsShndx() orelse continue;
|
||||
const shdr = self.shdrs.items[shndx];
|
||||
break :blk self.initOutputSection(elf_file, shdr) catch unreachable;
|
||||
};
|
||||
const shdr = &elf_file.shdrs.items[shndx];
|
||||
shdr.sh_info = atom.outputShndx().?;
|
||||
shdr.sh_info = atom_ptr.output_section_index;
|
||||
shdr.sh_link = elf_file.symtab_section_index.?;
|
||||
|
||||
const comp = elf_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
const gop = try elf_file.output_rela_sections.getOrPut(gpa, atom.outputShndx().?);
|
||||
const gop = try elf_file.output_rela_sections.getOrPut(gpa, atom_ptr.output_section_index);
|
||||
if (!gop.found_existing) gop.value_ptr.* = .{ .shndx = shndx };
|
||||
try gop.value_ptr.atom_list.append(gpa, atom_index);
|
||||
try gop.value_ptr.atom_list.append(gpa, .{ .index = atom_index, .file = self.index });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1041,7 +1077,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
|
||||
const isAlive = struct {
|
||||
fn isAlive(sym: *const Symbol, ctx: *Elf) bool {
|
||||
if (sym.mergeSubsection(ctx)) |msub| return msub.alive;
|
||||
if (sym.atom(ctx)) |atom_ptr| return atom_ptr.flags.alive;
|
||||
if (sym.atom(ctx)) |atom_ptr| return atom_ptr.alive;
|
||||
return true;
|
||||
}
|
||||
}.isAlive;
|
||||
@@ -1119,11 +1155,10 @@ pub fn globals(self: Object) []const Symbol.Index {
|
||||
|
||||
/// Returns atom's code and optionally uncompresses data if required (for compressed sections).
|
||||
/// Caller owns the memory.
|
||||
pub fn codeDecompressAlloc(self: Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
|
||||
pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
|
||||
const comp = elf_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
const atom_ptr = elf_file.atom(atom_index).?;
|
||||
assert(atom_ptr.file_index == self.index);
|
||||
const atom_ptr = self.atom(atom_index).?;
|
||||
const shdr = atom_ptr.inputShdr(elf_file);
|
||||
const handle = elf_file.fileHandle(self.file_handle);
|
||||
const data = try self.preadShdrContentsAlloc(gpa, handle, atom_ptr.input_section_index);
|
||||
@@ -1184,6 +1219,105 @@ fn preadRelocsAlloc(self: Object, allocator: Allocator, handle: std.fs.File, shn
|
||||
return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num];
|
||||
}
|
||||
|
||||
const AddAtomArgs = struct {
|
||||
name: u32,
|
||||
shndx: u32,
|
||||
size: u64,
|
||||
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));
|
||||
return self.addAtomAssumeCapacity(args);
|
||||
}
|
||||
|
||||
fn addAtomAssumeCapacity(self: *Object, args: AddAtomArgs) Atom.Index {
|
||||
const atom_index: Atom.Index = @intCast(self.atoms.items.len);
|
||||
const atom_ptr = self.atoms.addOneAssumeCapacity();
|
||||
atom_ptr.* = .{
|
||||
.atom_index = atom_index,
|
||||
.name_offset = args.name,
|
||||
.file_index = self.index,
|
||||
.input_section_index = args.shndx,
|
||||
.extra_index = self.addAtomExtraAssumeCapacity(.{}),
|
||||
.size = args.size,
|
||||
.alignment = args.alignment,
|
||||
};
|
||||
return atom_index;
|
||||
}
|
||||
|
||||
pub fn atom(self: *Object, atom_index: Atom.Index) ?*Atom {
|
||||
if (atom_index == 0) return null;
|
||||
assert(atom_index < self.atoms.items.len);
|
||||
return &self.atoms.items[atom_index];
|
||||
}
|
||||
|
||||
pub fn addAtomExtra(self: *Object, allocator: Allocator, extra: Atom.Extra) !u32 {
|
||||
const fields = @typeInfo(Atom.Extra).Struct.fields;
|
||||
try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
|
||||
return self.addAtomExtraAssumeCapacity(extra);
|
||||
}
|
||||
|
||||
pub fn addAtomExtraAssumeCapacity(self: *Object, extra: Atom.Extra) u32 {
|
||||
const index = @as(u32, @intCast(self.atoms_extra.items.len));
|
||||
const fields = @typeInfo(Atom.Extra).Struct.fields;
|
||||
inline for (fields) |field| {
|
||||
self.atoms_extra.appendAssumeCapacity(switch (field.type) {
|
||||
u32 => @field(extra, field.name),
|
||||
else => @compileError("bad field type"),
|
||||
});
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn atomExtra(self: *Object, index: u32) Atom.Extra {
|
||||
const fields = @typeInfo(Atom.Extra).Struct.fields;
|
||||
var i: usize = index;
|
||||
var result: Atom.Extra = undefined;
|
||||
inline for (fields) |field| {
|
||||
@field(result, field.name) = switch (field.type) {
|
||||
u32 => self.atoms_extra.items[i],
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn setAtomExtra(self: *Object, index: u32, extra: Atom.Extra) void {
|
||||
const fields = @typeInfo(Atom.Extra).Struct.fields;
|
||||
inline for (fields, 0..) |field, i| {
|
||||
self.atoms_extra.items[index + i] = switch (field.type) {
|
||||
u32 => @field(extra, field.name),
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn addInputMergeSection(self: *Object, allocator: Allocator) !InputMergeSection.Index {
|
||||
const index: InputMergeSection.Index = @intCast(self.input_merge_sections.items.len);
|
||||
const msec = try self.input_merge_sections.addOne(allocator);
|
||||
msec.* = .{};
|
||||
return index;
|
||||
}
|
||||
|
||||
fn inputMergeSection(self: *Object, index: InputMergeSection.Index) ?*InputMergeSection {
|
||||
if (index == 0) return null;
|
||||
return &self.input_merge_sections.items[index];
|
||||
}
|
||||
|
||||
fn addComdatGroup(self: *Object, allocator: Allocator) !Elf.ComdatGroup.Index {
|
||||
const index = @as(Elf.ComdatGroup.Index, @intCast(self.comdat_groups.items.len));
|
||||
_ = try self.comdat_groups.addOne(allocator);
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn comdatGroup(self: *Object, index: Elf.ComdatGroup.Index) *Elf.ComdatGroup {
|
||||
assert(index < self.comdat_groups.items.len);
|
||||
return &self.comdat_groups.items[index];
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: *Object,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
@@ -1247,9 +1381,9 @@ fn formatAtoms(
|
||||
_ = options;
|
||||
const object = ctx.object;
|
||||
try writer.writeAll(" atoms\n");
|
||||
for (object.atoms.items) |atom_index| {
|
||||
const atom = ctx.elf_file.atom(atom_index) orelse continue;
|
||||
try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
|
||||
for (object.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = object.atom(atom_index) orelse continue;
|
||||
try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1315,16 +1449,15 @@ fn formatComdatGroups(
|
||||
const object = ctx.object;
|
||||
const elf_file = ctx.elf_file;
|
||||
try writer.writeAll(" COMDAT groups\n");
|
||||
for (object.comdat_groups.items) |cg_index| {
|
||||
const cg = elf_file.comdatGroup(cg_index);
|
||||
const cg_owner = elf_file.comdatGroupOwner(cg.owner);
|
||||
if (cg_owner.file != object.index) continue;
|
||||
try writer.print(" COMDAT({d})\n", .{cg_index});
|
||||
for (object.comdat_groups.items, 0..) |cg, cg_index| {
|
||||
try writer.print(" COMDAT({d})", .{cg_index});
|
||||
if (!cg.alive) try writer.writeAll(" : [*]");
|
||||
try writer.writeByte('\n');
|
||||
const cg_members = cg.comdatGroupMembers(elf_file);
|
||||
for (cg_members) |shndx| {
|
||||
const atom_index = object.atoms.items[shndx];
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom.name(elf_file) });
|
||||
const atom_index = object.atoms_indexes.items[shndx];
|
||||
const atom_ptr = object.atom(atom_index) orelse continue;
|
||||
try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom_ptr.name(elf_file) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
|
||||
const global = elf_file.symbol(index);
|
||||
if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
|
||||
global.value = @intCast(this_sym.st_value);
|
||||
global.atom_index = 0;
|
||||
global.ref = .{ .index = 0, .file = 0 };
|
||||
global.esym_index = esym_index;
|
||||
global.version_index = self.versyms.items[esym_index];
|
||||
global.file_index = self.index;
|
||||
|
||||
@@ -9,10 +9,9 @@ name_offset: u32 = 0,
|
||||
/// Index of file where this symbol is defined.
|
||||
file_index: File.Index = 0,
|
||||
|
||||
/// Index of atom containing this symbol.
|
||||
/// Index of 0 means there is no associated atom with this symbol.
|
||||
/// Use `atom` to get the pointer to the atom.
|
||||
atom_index: Atom.Index = 0,
|
||||
/// Reference to Atom or merge subsection containing this symbol if any.
|
||||
/// Use `atom` or `mergeSubsection` to get the pointer to the atom.
|
||||
ref: Elf.Ref = .{ .index = 0, .file = 0 },
|
||||
|
||||
/// Assigned output section index for this symbol.
|
||||
output_section_index: u32 = 0,
|
||||
@@ -34,11 +33,15 @@ pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
|
||||
const file_ptr = symbol.file(elf_file).?;
|
||||
if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS;
|
||||
return !symbol.flags.import and symbol.atom(elf_file) == null and
|
||||
symbol.mergeSubsection(elf_file) == null and symbol.outputShndx() == null and
|
||||
symbol.mergeSubsection(elf_file) == null and symbol.outputShndx(elf_file) == null and
|
||||
file_ptr != .linker_defined;
|
||||
}
|
||||
|
||||
pub fn outputShndx(symbol: Symbol) ?u32 {
|
||||
pub fn outputShndx(symbol: Symbol, elf_file: *Elf) ?u32 {
|
||||
if (symbol.mergeSubsection(elf_file)) |msub|
|
||||
return if (msub.alive) msub.mergeSection(elf_file).output_section_index else null;
|
||||
if (symbol.atom(elf_file)) |atom_ptr|
|
||||
return if (atom_ptr.alive) atom_ptr.output_section_index else null;
|
||||
if (symbol.output_section_index == 0) return null;
|
||||
return symbol.output_section_index;
|
||||
}
|
||||
@@ -68,13 +71,15 @@ pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
|
||||
}
|
||||
|
||||
pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {
|
||||
return elf_file.atom(symbol.atom_index);
|
||||
if (symbol.flags.merge_subsection) return null;
|
||||
const file_ptr = elf_file.file(symbol.ref.file) orelse return null;
|
||||
return file_ptr.atom(symbol.ref.index);
|
||||
}
|
||||
|
||||
pub fn mergeSubsection(symbol: Symbol, elf_file: *Elf) ?*MergeSubsection {
|
||||
if (!symbol.flags.merge_subsection) return null;
|
||||
const extras = symbol.extra(elf_file).?;
|
||||
return elf_file.mergeSubsection(extras.subsection);
|
||||
const msec = elf_file.mergeSection(symbol.ref.file);
|
||||
return msec.mergeSubsection(symbol.ref.index);
|
||||
}
|
||||
|
||||
pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
|
||||
@@ -116,7 +121,7 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
|
||||
return symbol.pltAddress(elf_file);
|
||||
}
|
||||
if (symbol.atom(elf_file)) |atom_ptr| {
|
||||
if (!atom_ptr.flags.alive) {
|
||||
if (!atom_ptr.alive) {
|
||||
if (mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame")) {
|
||||
const sym_name = symbol.name(elf_file);
|
||||
const sh_addr, const sh_size = blk: {
|
||||
@@ -258,7 +263,6 @@ const AddExtraOpts = struct {
|
||||
gottp: ?u32 = null,
|
||||
tlsdesc: ?u32 = null,
|
||||
zig_got: ?u32 = null,
|
||||
subsection: ?u32 = null,
|
||||
};
|
||||
|
||||
pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void {
|
||||
@@ -298,7 +302,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
|
||||
if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;
|
||||
if (symbol.mergeSubsection(elf_file)) |msub| break :blk @intCast(msub.mergeSection(elf_file).output_section_index);
|
||||
if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS;
|
||||
break :blk @intCast(symbol.outputShndx() orelse elf.SHN_UNDEF);
|
||||
break :blk @intCast(symbol.outputShndx(elf_file) orelse elf.SHN_UNDEF);
|
||||
};
|
||||
const st_value = blk: {
|
||||
if (symbol.flags.has_copy_rel) break :blk symbol.address(.{}, elf_file);
|
||||
@@ -382,22 +386,23 @@ fn format2(
|
||||
_ = options;
|
||||
_ = unused_fmt_string;
|
||||
const symbol = ctx.symbol;
|
||||
const elf_file = ctx.elf_file;
|
||||
try writer.print("%{d} : {s} : @{x}", .{
|
||||
symbol.esym_index,
|
||||
symbol.fmtName(ctx.elf_file),
|
||||
symbol.address(.{}, ctx.elf_file),
|
||||
symbol.fmtName(elf_file),
|
||||
symbol.address(.{}, elf_file),
|
||||
});
|
||||
if (symbol.file(ctx.elf_file)) |file_ptr| {
|
||||
if (symbol.isAbs(ctx.elf_file)) {
|
||||
if (symbol.elfSym(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {
|
||||
if (symbol.file(elf_file)) |file_ptr| {
|
||||
if (symbol.isAbs(elf_file)) {
|
||||
if (symbol.elfSym(elf_file).st_shndx == elf.SHN_UNDEF) {
|
||||
try writer.writeAll(" : undef");
|
||||
} else {
|
||||
try writer.writeAll(" : absolute");
|
||||
}
|
||||
} else if (symbol.outputShndx()) |shndx| {
|
||||
} else if (symbol.outputShndx(elf_file)) |shndx| {
|
||||
try writer.print(" : shdr({d})", .{shndx});
|
||||
}
|
||||
if (symbol.atom(ctx.elf_file)) |atom_ptr| {
|
||||
if (symbol.atom(elf_file)) |atom_ptr| {
|
||||
try writer.print(" : atom({d})", .{atom_ptr.atom_index});
|
||||
}
|
||||
var buf: [2]u8 = .{'_'} ** 2;
|
||||
@@ -483,7 +488,7 @@ pub const Extra = struct {
|
||||
gottp: u32 = 0,
|
||||
tlsdesc: u32 = 0,
|
||||
zig_got: u32 = 0,
|
||||
subsection: u32 = 0,
|
||||
merge_section: u32 = 0,
|
||||
};
|
||||
|
||||
pub const Index = u32;
|
||||
|
||||
@@ -15,7 +15,9 @@ local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||
globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
|
||||
|
||||
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
|
||||
atoms: std.ArrayListUnmanaged(Atom) = .{},
|
||||
atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
|
||||
atoms_extra: std.ArrayListUnmanaged(u32) = .{},
|
||||
relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
|
||||
|
||||
num_dynrelocs: u32 = 0,
|
||||
@@ -80,7 +82,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
|
||||
const comp = elf_file.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
|
||||
try self.atoms.append(gpa, 0); // null input section
|
||||
try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section
|
||||
try self.relocs.append(gpa, .{}); // null relocs section
|
||||
try self.strtab.buffer.append(gpa, 0);
|
||||
|
||||
@@ -117,6 +119,8 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void {
|
||||
self.global_symbols.deinit(allocator);
|
||||
self.globals_lookup.deinit(allocator);
|
||||
self.atoms.deinit(allocator);
|
||||
self.atoms_indexes.deinit(allocator);
|
||||
self.atoms_extra.deinit(allocator);
|
||||
for (self.relocs.items) |*list| {
|
||||
list.deinit(allocator);
|
||||
}
|
||||
@@ -276,24 +280,20 @@ pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
|
||||
return index | global_symbol_bit;
|
||||
}
|
||||
|
||||
pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
|
||||
pub fn newAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
const atom_index = try elf_file.addAtom();
|
||||
const atom_index = try self.addAtom(gpa);
|
||||
const symbol_index = try elf_file.addSymbol();
|
||||
const esym_index = try self.addLocalEsym(gpa);
|
||||
|
||||
const shndx = @as(u32, @intCast(self.atoms.items.len));
|
||||
try self.atoms.append(gpa, atom_index);
|
||||
try self.atoms_indexes.append(gpa, atom_index);
|
||||
try self.local_symbols.append(gpa, symbol_index);
|
||||
|
||||
const atom_ptr = elf_file.atom(atom_index).?;
|
||||
atom_ptr.file_index = self.index;
|
||||
|
||||
const symbol_ptr = elf_file.symbol(symbol_index);
|
||||
symbol_ptr.file_index = self.index;
|
||||
symbol_ptr.atom_index = atom_index;
|
||||
symbol_ptr.ref = .{ .index = atom_index, .file = self.index };
|
||||
|
||||
self.local_esyms.items(.shndx)[esym_index] = shndx;
|
||||
self.local_esyms.items(.shndx)[esym_index] = atom_index;
|
||||
self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;
|
||||
symbol_ptr.esym_index = esym_index;
|
||||
|
||||
@@ -301,21 +301,22 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
|
||||
const relocs_index = @as(u32, @intCast(self.relocs.items.len));
|
||||
const relocs = try self.relocs.addOne(gpa);
|
||||
relocs.* = .{};
|
||||
|
||||
const atom_ptr = self.atom(atom_index).?;
|
||||
atom_ptr.relocs_section_index = relocs_index;
|
||||
|
||||
return symbol_index;
|
||||
}
|
||||
|
||||
/// TODO actually create fake input shdrs and return that instead.
|
||||
pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr {
|
||||
_ = self;
|
||||
const atom = elf_file.atom(atom_index) orelse return Elf.null_shdr;
|
||||
const shndx = atom.outputShndx() orelse return Elf.null_shdr;
|
||||
pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr {
|
||||
const atom_ptr = self.atom(atom_index) orelse return Elf.null_shdr;
|
||||
const shndx = atom_ptr.output_section_index;
|
||||
var shdr = elf_file.shdrs.items[shndx];
|
||||
shdr.sh_addr = 0;
|
||||
shdr.sh_offset = 0;
|
||||
shdr.sh_size = atom.size;
|
||||
shdr.sh_addralign = atom.alignment.toByteUnits() orelse 1;
|
||||
shdr.sh_size = atom_ptr.size;
|
||||
shdr.sh_addralign = atom_ptr.alignment.toByteUnits() orelse 1;
|
||||
return shdr;
|
||||
}
|
||||
|
||||
@@ -329,27 +330,21 @@ pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
|
||||
|
||||
if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
|
||||
assert(esym.st_shndx == SHN_ATOM);
|
||||
const atom_index = self.atoms.items[shndx];
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const atom_ptr = self.atom(shndx) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
}
|
||||
|
||||
const global = elf_file.symbol(index);
|
||||
if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {
|
||||
const atom_index = switch (esym.st_shndx) {
|
||||
elf.SHN_ABS, elf.SHN_COMMON => 0,
|
||||
SHN_ATOM => self.atoms.items[shndx],
|
||||
SHN_ATOM => shndx,
|
||||
else => unreachable,
|
||||
};
|
||||
const output_section_index = if (elf_file.atom(atom_index)) |atom|
|
||||
atom.outputShndx().?
|
||||
else
|
||||
elf.SHN_UNDEF;
|
||||
global.value = @intCast(esym.st_value);
|
||||
global.atom_index = atom_index;
|
||||
global.ref = .{ .index = atom_index, .file = self.index };
|
||||
global.esym_index = esym_index;
|
||||
global.file_index = self.index;
|
||||
global.output_section_index = output_section_index;
|
||||
global.version_index = elf_file.default_sym_version;
|
||||
if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;
|
||||
}
|
||||
@@ -376,7 +371,7 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
|
||||
};
|
||||
|
||||
global.value = 0;
|
||||
global.atom_index = 0;
|
||||
global.ref = .{ .index = 0, .file = 0 };
|
||||
global.esym_index = esym_index;
|
||||
global.file_index = self.index;
|
||||
global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
|
||||
@@ -397,7 +392,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
|
||||
}
|
||||
|
||||
global.value = 0;
|
||||
global.atom_index = 0;
|
||||
global.ref = .{ .index = 0, .file = 0 };
|
||||
global.esym_index = esym_index;
|
||||
global.file_index = self.index;
|
||||
}
|
||||
@@ -405,19 +400,19 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
|
||||
|
||||
pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
for (self.atoms.items) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const shdr = atom.inputShdr(elf_file);
|
||||
for (self.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
const shdr = atom_ptr.inputShdr(elf_file);
|
||||
if (shdr.sh_type == elf.SHT_NOBITS) continue;
|
||||
if (atom.scanRelocsRequiresCode(elf_file)) {
|
||||
if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
|
||||
// TODO ideally we don't have to fetch the code here.
|
||||
// Perhaps it would make sense to save the code until flushModule where we
|
||||
// would free all of generated code?
|
||||
const code = try self.codeAlloc(elf_file, atom_index);
|
||||
defer gpa.free(code);
|
||||
try atom.scanRelocs(elf_file, code, undefs);
|
||||
} else try atom.scanRelocs(elf_file, null, undefs);
|
||||
try atom_ptr.scanRelocs(elf_file, code, undefs);
|
||||
} else try atom_ptr.scanRelocs(elf_file, null, undefs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,9 +445,8 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O
|
||||
esym.st_shndx == elf.SHN_COMMON) continue;
|
||||
|
||||
if (esym.st_shndx == SHN_ATOM) {
|
||||
const atom_index = self.atoms.items[shndx];
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const atom_ptr = self.atom(shndx) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
}
|
||||
|
||||
const gop = try dupes.getOrPut(index);
|
||||
@@ -493,7 +487,7 @@ pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *
|
||||
const global = elf_file.symbol(global_index);
|
||||
const file_ptr = global.file(elf_file).?;
|
||||
assert(file_ptr.index() == self.index);
|
||||
if (global.outputShndx() == null) continue;
|
||||
if (global.outputShndx(elf_file) == null) continue;
|
||||
|
||||
const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));
|
||||
ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });
|
||||
@@ -517,20 +511,20 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void {
|
||||
try writer.writeAll(self.data.items);
|
||||
}
|
||||
|
||||
pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {
|
||||
for (self.atoms.items) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const rela_shndx = atom.relocsShndx() orelse continue;
|
||||
pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
|
||||
for (self.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
const rela_shndx = atom_ptr.relocsShndx() orelse continue;
|
||||
// TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level
|
||||
if (self.relocs.items[rela_shndx].items.len == 0) continue;
|
||||
const out_shndx = atom.outputShndx().?;
|
||||
const out_shndx = atom_ptr.output_section_index;
|
||||
const out_shdr = elf_file.shdrs.items[out_shndx];
|
||||
if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
|
||||
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;
|
||||
try sec.atom_list.append(gpa, atom_index);
|
||||
try sec.atom_list.append(gpa, .{ .index = atom_index, .file = self.index });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,7 +555,7 @@ pub fn globals(self: ZigObject) []const Symbol.Index {
|
||||
pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
|
||||
for (self.locals()) |local_index| {
|
||||
const local = elf_file.symbol(local_index);
|
||||
if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
|
||||
if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
|
||||
const esym = local.elfSym(elf_file);
|
||||
switch (esym.st_type()) {
|
||||
elf.STT_SECTION, elf.STT_NOTYPE => continue,
|
||||
@@ -577,7 +571,7 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
|
||||
const global = elf_file.symbol(global_index);
|
||||
const file_ptr = global.file(elf_file) orelse continue;
|
||||
if (file_ptr.index() != self.index) continue;
|
||||
if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
|
||||
if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
|
||||
global.flags.output_symtab = true;
|
||||
if (global.isLocal(elf_file)) {
|
||||
try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
|
||||
@@ -621,11 +615,10 @@ pub fn asFile(self: *ZigObject) File {
|
||||
|
||||
/// Returns atom's code.
|
||||
/// Caller owns the memory.
|
||||
pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
|
||||
pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
const atom = elf_file.atom(atom_index).?;
|
||||
assert(atom.file_index == self.index);
|
||||
const shdr = &elf_file.shdrs.items[atom.outputShndx().?];
|
||||
const atom_ptr = self.atom(atom_index).?;
|
||||
const shdr = &elf_file.shdrs.items[atom_ptr.output_section_index];
|
||||
|
||||
if (shdr.sh_flags & elf.SHF_TLS != 0) {
|
||||
const tlv = self.tls_variables.get(atom_index).?;
|
||||
@@ -633,13 +626,13 @@ pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8
|
||||
return code;
|
||||
}
|
||||
|
||||
const file_offset = shdr.sh_offset + @as(u64, @intCast(atom.value));
|
||||
const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
|
||||
const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
|
||||
const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow;
|
||||
const code = try gpa.alloc(u8, size);
|
||||
errdefer gpa.free(code);
|
||||
const amt = try elf_file.base.file.?.preadAll(code, file_offset);
|
||||
if (amt != code.len) {
|
||||
log.err("fetching code for {s} failed", .{atom.name(elf_file)});
|
||||
log.err("fetching code for {s} failed", .{atom_ptr.name(elf_file)});
|
||||
return error.InputOutput;
|
||||
}
|
||||
return code;
|
||||
@@ -760,7 +753,7 @@ pub fn getOrCreateMetadataForLazySymbol(
|
||||
};
|
||||
switch (metadata.state.*) {
|
||||
.unused => {
|
||||
const symbol_index = try self.addAtom(elf_file);
|
||||
const symbol_index = try self.newAtom(elf_file);
|
||||
const sym = elf_file.symbol(symbol_index);
|
||||
sym.flags.needs_zig_got = true;
|
||||
metadata.symbol_index.* = symbol_index;
|
||||
@@ -824,7 +817,7 @@ pub fn getOrCreateMetadataForDecl(
|
||||
const gop = try self.decls.getOrPut(gpa, decl_index);
|
||||
if (!gop.found_existing) {
|
||||
const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
|
||||
const symbol_index = try self.addAtom(elf_file);
|
||||
const symbol_index = try self.newAtom(elf_file);
|
||||
const mod = elf_file.base.comp.module.?;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const sym = elf_file.symbol(symbol_index);
|
||||
@@ -861,14 +854,14 @@ fn getDeclShdrIndex(
|
||||
if (is_all_zeroes) break :blk elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{
|
||||
.type = elf.SHT_NOBITS,
|
||||
.flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
|
||||
.name = ".tbss",
|
||||
.name = try elf_file.insertShString(".tbss"),
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
|
||||
break :blk elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
|
||||
.name = ".tdata",
|
||||
.name = try elf_file.insertShString(".tdata"),
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
}
|
||||
@@ -919,14 +912,13 @@ fn updateDeclCode(
|
||||
const sym = elf_file.symbol(sym_index);
|
||||
const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
|
||||
const atom_ptr = sym.atom(elf_file).?;
|
||||
const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
|
||||
|
||||
sym.output_section_index = shdr_index;
|
||||
atom_ptr.alive = true;
|
||||
atom_ptr.name_offset = name_offset;
|
||||
atom_ptr.output_section_index = shdr_index;
|
||||
|
||||
sym.name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
|
||||
atom_ptr.flags.alive = true;
|
||||
atom_ptr.name_offset = sym.name_offset;
|
||||
esym.st_name = sym.name_offset;
|
||||
sym.name_offset = name_offset;
|
||||
esym.st_name = name_offset;
|
||||
esym.st_info |= stt_bits;
|
||||
esym.st_size = code.len;
|
||||
|
||||
@@ -1018,16 +1010,17 @@ fn updateTlv(
|
||||
const sym = elf_file.symbol(sym_index);
|
||||
const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
|
||||
const atom_ptr = sym.atom(elf_file).?;
|
||||
const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
|
||||
|
||||
sym.value = 0;
|
||||
sym.output_section_index = shndx;
|
||||
atom_ptr.output_section_index = shndx;
|
||||
sym.name_offset = name_offset;
|
||||
|
||||
atom_ptr.output_section_index = shndx;
|
||||
atom_ptr.alive = true;
|
||||
atom_ptr.name_offset = name_offset;
|
||||
|
||||
sym.name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
|
||||
atom_ptr.flags.alive = true;
|
||||
atom_ptr.name_offset = sym.name_offset;
|
||||
esym.st_value = 0;
|
||||
esym.st_name = sym.name_offset;
|
||||
esym.st_name = name_offset;
|
||||
esym.st_info = elf.STT_TLS;
|
||||
esym.st_size = code.len;
|
||||
|
||||
@@ -1048,7 +1041,7 @@ fn updateTlv(
|
||||
{
|
||||
const gop = try elf_file.output_sections.getOrPut(gpa, atom_ptr.output_section_index);
|
||||
if (!gop.found_existing) gop.value_ptr.* = .{};
|
||||
try gop.value_ptr.append(gpa, atom_ptr.atom_index);
|
||||
try gop.value_ptr.append(gpa, .{ .index = atom_ptr.atom_index, .file = self.index });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1242,13 +1235,12 @@ fn updateLazySymbol(
|
||||
};
|
||||
const local_sym = elf_file.symbol(symbol_index);
|
||||
local_sym.name_offset = name_str_index;
|
||||
local_sym.output_section_index = output_section_index;
|
||||
const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
|
||||
local_esym.st_name = name_str_index;
|
||||
local_esym.st_info |= elf.STT_OBJECT;
|
||||
local_esym.st_size = code.len;
|
||||
const atom_ptr = local_sym.atom(elf_file).?;
|
||||
atom_ptr.flags.alive = true;
|
||||
atom_ptr.alive = true;
|
||||
atom_ptr.name_offset = name_str_index;
|
||||
atom_ptr.alignment = required_alignment;
|
||||
atom_ptr.size = code.len;
|
||||
@@ -1307,8 +1299,7 @@ pub fn lowerUnnamedConst(
|
||||
return error.CodegenFail;
|
||||
},
|
||||
};
|
||||
const sym = elf_file.symbol(sym_index);
|
||||
try unnamed_consts.append(gpa, sym.atom_index);
|
||||
try unnamed_consts.append(gpa, sym_index);
|
||||
return sym_index;
|
||||
}
|
||||
|
||||
@@ -1332,7 +1323,7 @@ fn lowerConst(
|
||||
var code_buffer = std.ArrayList(u8).init(gpa);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
const sym_index = try self.addAtom(elf_file);
|
||||
const sym_index = try self.newAtom(elf_file);
|
||||
|
||||
const res = try codegen.generateSymbol(
|
||||
&elf_file.base,
|
||||
@@ -1351,13 +1342,12 @@ fn lowerConst(
|
||||
const local_sym = elf_file.symbol(sym_index);
|
||||
const name_str_index = try self.strtab.insert(gpa, name);
|
||||
local_sym.name_offset = name_str_index;
|
||||
local_sym.output_section_index = output_section_index;
|
||||
const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
|
||||
local_esym.st_name = name_str_index;
|
||||
local_esym.st_info |= elf.STT_OBJECT;
|
||||
local_esym.st_size = code.len;
|
||||
const atom_ptr = local_sym.atom(elf_file).?;
|
||||
atom_ptr.flags.alive = true;
|
||||
atom_ptr.alive = true;
|
||||
atom_ptr.name_offset = name_str_index;
|
||||
atom_ptr.alignment = required_alignment;
|
||||
atom_ptr.size = code.len;
|
||||
@@ -1530,6 +1520,72 @@ pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
|
||||
return self.strtab.getAssumeExists(off);
|
||||
}
|
||||
|
||||
fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
|
||||
try self.atoms.ensureUnusedCapacity(allocator, 1);
|
||||
try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
|
||||
return self.addAtomAssumeCapacity();
|
||||
}
|
||||
|
||||
fn addAtomAssumeCapacity(self: *ZigObject) Atom.Index {
|
||||
const atom_index: Atom.Index = @intCast(self.atoms.items.len);
|
||||
const atom_ptr = self.atoms.addOneAssumeCapacity();
|
||||
atom_ptr.* = .{
|
||||
.file_index = self.index,
|
||||
.atom_index = atom_index,
|
||||
.extra_index = self.addAtomExtraAssumeCapacity(.{}),
|
||||
};
|
||||
return atom_index;
|
||||
}
|
||||
|
||||
pub fn atom(self: *ZigObject, atom_index: Atom.Index) ?*Atom {
|
||||
if (atom_index == 0) return null;
|
||||
assert(atom_index < self.atoms.items.len);
|
||||
return &self.atoms.items[atom_index];
|
||||
}
|
||||
|
||||
fn addAtomExtra(self: *ZigObject, allocator: Allocator, extra: Atom.Extra) !u32 {
|
||||
const fields = @typeInfo(Atom.Extra).Struct.fields;
|
||||
try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
|
||||
return self.addAtomExtraAssumeCapacity(extra);
|
||||
}
|
||||
|
||||
fn addAtomExtraAssumeCapacity(self: *ZigObject, extra: Atom.Extra) u32 {
|
||||
const index = @as(u32, @intCast(self.atoms_extra.items.len));
|
||||
const fields = @typeInfo(Atom.Extra).Struct.fields;
|
||||
inline for (fields) |field| {
|
||||
self.atoms_extra.appendAssumeCapacity(switch (field.type) {
|
||||
u32 => @field(extra, field.name),
|
||||
else => @compileError("bad field type"),
|
||||
});
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn atomExtra(self: ZigObject, index: u32) Atom.Extra {
|
||||
const fields = @typeInfo(Atom.Extra).Struct.fields;
|
||||
var i: usize = index;
|
||||
var result: Atom.Extra = undefined;
|
||||
inline for (fields) |field| {
|
||||
@field(result, field.name) = switch (field.type) {
|
||||
u32 => self.atoms_extra.items[i],
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {
|
||||
assert(index > 0);
|
||||
const fields = @typeInfo(Atom.Extra).Struct.fields;
|
||||
inline for (fields, 0..) |field, i| {
|
||||
self.atoms_extra.items[index + i] = switch (field.type) {
|
||||
u32 => @field(extra, field.name),
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
|
||||
return .{ .data = .{
|
||||
.self = self,
|
||||
@@ -1578,9 +1634,9 @@ fn formatAtoms(
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
try writer.writeAll(" atoms\n");
|
||||
for (ctx.self.atoms.items) |atom_index| {
|
||||
const atom = ctx.elf_file.atom(atom_index) orelse continue;
|
||||
try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
|
||||
for (ctx.self.atoms_indexes.items) |atom_index| {
|
||||
const atom_ptr = ctx.self.atom(atom_index) orelse continue;
|
||||
try writer.print(" {}\n", .{atom_ptr.fmt(ctx.elf_file)});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@ pub const Fde = struct {
|
||||
const object = elf_file.file(fde.file_index).?.object;
|
||||
const rel = fde.relocs(elf_file)[0];
|
||||
const sym = object.symtab.items[rel.r_sym()];
|
||||
const atom_index = object.atoms.items[sym.st_shndx];
|
||||
return elf_file.atom(atom_index).?;
|
||||
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 {
|
||||
@@ -421,7 +421,7 @@ fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Re
|
||||
switch (sym.type(elf_file)) {
|
||||
elf.STT_SECTION => {
|
||||
r_addend += @intCast(sym.address(.{}, elf_file));
|
||||
r_sym = elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx().?);
|
||||
r_sym = elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx(elf_file).?);
|
||||
},
|
||||
else => {
|
||||
r_sym = sym.outputSymtabIndex(elf_file) orelse 0;
|
||||
|
||||
@@ -98,11 +98,34 @@ pub const File = union(enum) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn atom(file: File, atom_index: Atom.Index) ?*Atom {
|
||||
return switch (file) {
|
||||
.shared_object => unreachable,
|
||||
.linker_defined => null,
|
||||
inline else => |x| x.atom(atom_index),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn atoms(file: File) []const Atom.Index {
|
||||
return switch (file) {
|
||||
.linker_defined, .shared_object => &[0]Atom.Index{},
|
||||
.zig_object => |x| x.atoms.items,
|
||||
.object => |x| x.atoms.items,
|
||||
.shared_object => unreachable,
|
||||
.linker_defined => &[0]Atom.Index{},
|
||||
.zig_object => |x| x.atoms_indexes.items,
|
||||
.object => |x| x.atoms_indexes.items,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn atomExtra(file: File, extra_index: u32) Atom.Extra {
|
||||
return switch (file) {
|
||||
.shared_object, .linker_defined => unreachable,
|
||||
inline else => |x| x.atomExtra(extra_index),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn setAtomExtra(file: File, extra_index: u32, extra: Atom.Extra) void {
|
||||
return switch (file) {
|
||||
.shared_object, .linker_defined => unreachable,
|
||||
inline else => |x| x.setAtomExtra(extra_index, extra),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -114,6 +137,13 @@ pub const File = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn comdatGroup(file: File, ind: Elf.ComdatGroup.Index) *Elf.ComdatGroup {
|
||||
return switch (file) {
|
||||
.linker_defined, .shared_object, .zig_object => unreachable,
|
||||
.object => |x| x.comdatGroup(ind),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index {
|
||||
return switch (file) {
|
||||
.zig_object => |x| x.symbol(ind),
|
||||
@@ -134,6 +164,12 @@ pub const File = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getString(file: File, off: u32) [:0]const u8 {
|
||||
return switch (file) {
|
||||
inline else => |x| x.getString(off),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn updateSymtabSize(file: File, elf_file: *Elf) !void {
|
||||
return switch (file) {
|
||||
inline else => |x| x.updateSymtabSize(elf_file),
|
||||
|
||||
@@ -16,9 +16,11 @@ pub fn gcAtoms(elf_file: *Elf) !void {
|
||||
}
|
||||
|
||||
fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_file: *Elf) !void {
|
||||
if (elf_file.entry_index) |index| {
|
||||
const global = elf_file.symbol(index);
|
||||
try markSymbol(global, roots, elf_file);
|
||||
if (elf_file.linkerDefinedPtr()) |obj| {
|
||||
if (obj.entry_index) |index| {
|
||||
const global = elf_file.symbol(index);
|
||||
try markSymbol(global, roots, elf_file);
|
||||
}
|
||||
}
|
||||
|
||||
for (files) |index| {
|
||||
@@ -35,8 +37,8 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil
|
||||
const file = elf_file.file(index).?;
|
||||
|
||||
for (file.atoms()) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive) continue;
|
||||
const atom = file.atom(atom_index) orelse continue;
|
||||
if (!atom.alive) continue;
|
||||
|
||||
const shdr = atom.inputShdr(elf_file);
|
||||
const name = atom.name(elf_file);
|
||||
@@ -54,7 +56,7 @@ fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_fil
|
||||
break :blk false;
|
||||
};
|
||||
if (is_gc_root and markAtom(atom)) try roots.append(atom);
|
||||
if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.flags.visited = true;
|
||||
if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.visited = true;
|
||||
}
|
||||
|
||||
// Mark every atom referenced by CIE as alive.
|
||||
@@ -77,22 +79,22 @@ fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), elf_file: *Elf) !void
|
||||
}
|
||||
|
||||
fn markAtom(atom: *Atom) bool {
|
||||
const already_visited = atom.flags.visited;
|
||||
atom.flags.visited = true;
|
||||
return atom.flags.alive and !already_visited;
|
||||
const already_visited = atom.visited;
|
||||
atom.visited = true;
|
||||
return atom.alive and !already_visited;
|
||||
}
|
||||
|
||||
fn markLive(atom: *Atom, elf_file: *Elf) void {
|
||||
if (@import("build_options").enable_logging) track_live_level.incr();
|
||||
|
||||
assert(atom.flags.visited);
|
||||
assert(atom.visited);
|
||||
const file = atom.file(elf_file).?;
|
||||
|
||||
for (atom.fdes(elf_file)) |fde| {
|
||||
for (fde.relocs(elf_file)[1..]) |rel| {
|
||||
const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));
|
||||
const target_atom = target_sym.atom(elf_file) orelse continue;
|
||||
target_atom.flags.alive = true;
|
||||
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);
|
||||
}
|
||||
@@ -105,7 +107,7 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
|
||||
continue;
|
||||
}
|
||||
const target_atom = target_sym.atom(elf_file) orelse continue;
|
||||
target_atom.flags.alive = true;
|
||||
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);
|
||||
}
|
||||
@@ -120,10 +122,11 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {
|
||||
|
||||
fn prune(files: []const File.Index, elf_file: *Elf) void {
|
||||
for (files) |index| {
|
||||
for (elf_file.file(index).?.atoms()) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (atom.flags.alive and !atom.flags.visited) {
|
||||
atom.flags.alive = false;
|
||||
const file = elf_file.file(index).?;
|
||||
for (file.atoms()) |atom_index| {
|
||||
const atom = file.atom(atom_index) orelse continue;
|
||||
if (atom.alive and !atom.visited) {
|
||||
atom.alive = false;
|
||||
atom.markFdesDead(elf_file);
|
||||
}
|
||||
}
|
||||
@@ -133,9 +136,10 @@ fn prune(files: []const File.Index, elf_file: *Elf) void {
|
||||
pub fn dumpPrunedAtoms(elf_file: *Elf) !void {
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
for (elf_file.objects.items) |index| {
|
||||
for (elf_file.file(index).?.object.atoms.items) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom.flags.alive)
|
||||
const file = elf_file.file(index).?;
|
||||
for (file.atoms()) |atom_index| {
|
||||
const atom = file.atom(atom_index) orelse continue;
|
||||
if (!atom.alive)
|
||||
// TODO should we simply print to stderr?
|
||||
try stderr.print("link: removing unused section '{s}' in file '{}'\n", .{
|
||||
atom.name(elf_file),
|
||||
|
||||
@@ -10,16 +10,18 @@ pub const MergeSection = struct {
|
||||
IndexContext,
|
||||
std.hash_map.default_max_load_percentage,
|
||||
) = .{},
|
||||
subsections: std.ArrayListUnmanaged(MergeSubsection.Index) = .{},
|
||||
subsections: std.ArrayListUnmanaged(MergeSubsection) = .{},
|
||||
finalized_subsections: std.ArrayListUnmanaged(MergeSubsection.Index) = .{},
|
||||
|
||||
pub fn deinit(msec: *MergeSection, allocator: Allocator) void {
|
||||
msec.bytes.deinit(allocator);
|
||||
msec.table.deinit(allocator);
|
||||
msec.subsections.deinit(allocator);
|
||||
msec.finalized_subsections.deinit(allocator);
|
||||
}
|
||||
|
||||
pub fn name(msec: MergeSection, elf_file: *Elf) [:0]const u8 {
|
||||
return elf_file.strings.getAssumeExists(msec.name_offset);
|
||||
return elf_file.getShString(msec.name_offset);
|
||||
}
|
||||
|
||||
pub fn address(msec: MergeSection, elf_file: *Elf) i64 {
|
||||
@@ -58,25 +60,26 @@ pub const MergeSection = struct {
|
||||
|
||||
/// Finalizes the merge section and clears hash table.
|
||||
/// Sorts all owned subsections.
|
||||
pub fn finalize(msec: *MergeSection, elf_file: *Elf) !void {
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
try msec.subsections.ensureTotalCapacityPrecise(gpa, msec.table.count());
|
||||
pub fn finalize(msec: *MergeSection, allocator: Allocator) !void {
|
||||
try msec.finalized_subsections.ensureTotalCapacityPrecise(allocator, msec.subsections.items.len);
|
||||
|
||||
var it = msec.table.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const msub = elf_file.mergeSubsection(entry.value_ptr.*);
|
||||
const msub = msec.mergeSubsection(entry.value_ptr.*);
|
||||
if (!msub.alive) continue;
|
||||
msec.subsections.appendAssumeCapacity(entry.value_ptr.*);
|
||||
msec.finalized_subsections.appendAssumeCapacity(entry.value_ptr.*);
|
||||
}
|
||||
msec.table.clearAndFree(gpa);
|
||||
msec.table.clearAndFree(allocator);
|
||||
|
||||
const sortFn = struct {
|
||||
pub fn sortFn(ctx: *Elf, lhs: MergeSubsection.Index, rhs: MergeSubsection.Index) bool {
|
||||
pub fn sortFn(ctx: *MergeSection, lhs: MergeSubsection.Index, rhs: MergeSubsection.Index) bool {
|
||||
const lhs_msub = ctx.mergeSubsection(lhs);
|
||||
const rhs_msub = ctx.mergeSubsection(rhs);
|
||||
if (lhs_msub.alignment.compareStrict(.eq, rhs_msub.alignment)) {
|
||||
if (lhs_msub.size == rhs_msub.size) {
|
||||
return mem.order(u8, lhs_msub.getString(ctx), rhs_msub.getString(ctx)) == .lt;
|
||||
const lhs_string = ctx.bytes.items[lhs_msub.string_index..][0..lhs_msub.size];
|
||||
const rhs_string = ctx.bytes.items[rhs_msub.string_index..][0..rhs_msub.size];
|
||||
return mem.order(u8, lhs_string, rhs_string) == .lt;
|
||||
}
|
||||
return lhs_msub.size < rhs_msub.size;
|
||||
}
|
||||
@@ -84,7 +87,19 @@ pub const MergeSection = struct {
|
||||
}
|
||||
}.sortFn;
|
||||
|
||||
std.mem.sort(MergeSubsection.Index, msec.subsections.items, elf_file, sortFn);
|
||||
std.mem.sort(MergeSubsection.Index, msec.finalized_subsections.items, msec, sortFn);
|
||||
}
|
||||
|
||||
pub fn addMergeSubsection(msec: *MergeSection, allocator: Allocator) !MergeSubsection.Index {
|
||||
const index: MergeSubsection.Index = @intCast(msec.subsections.items.len);
|
||||
const msub = try msec.subsections.addOne(allocator);
|
||||
msub.* = .{};
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn mergeSubsection(msec: *MergeSection, index: MergeSubsection.Index) *MergeSubsection {
|
||||
assert(index < msec.subsections.items.len);
|
||||
return &msec.subsections.items[index];
|
||||
}
|
||||
|
||||
pub const IndexContext = struct {
|
||||
@@ -154,8 +169,8 @@ pub const MergeSection = struct {
|
||||
msec.type,
|
||||
msec.flags,
|
||||
});
|
||||
for (msec.subsections.items) |index| {
|
||||
try writer.print(" {}\n", .{elf_file.mergeSubsection(index).fmt(elf_file)});
|
||||
for (msec.subsections.items) |msub| {
|
||||
try writer.print(" {}\n", .{msub.fmt(elf_file)});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,18 +265,26 @@ pub const InputMergeSection = struct {
|
||||
// TODO: imsec.strings.clearAndFree(allocator);
|
||||
}
|
||||
|
||||
pub fn findSubsection(imsec: InputMergeSection, offset: u32) ?struct { MergeSubsection.Index, u32 } {
|
||||
const FindSubsectionResult = struct {
|
||||
msub_index: MergeSubsection.Index,
|
||||
offset: u32,
|
||||
};
|
||||
|
||||
pub fn findSubsection(imsec: InputMergeSection, offset: u32) ?FindSubsectionResult {
|
||||
// TODO: binary search
|
||||
for (imsec.offsets.items, 0..) |off, index| {
|
||||
if (offset < off) return .{
|
||||
imsec.subsections.items[index - 1],
|
||||
offset - imsec.offsets.items[index - 1],
|
||||
.msub_index = imsec.subsections.items[index - 1],
|
||||
.offset = offset - imsec.offsets.items[index - 1],
|
||||
};
|
||||
}
|
||||
const last = imsec.offsets.items.len - 1;
|
||||
const last_off = imsec.offsets.items[last];
|
||||
const last_len = imsec.strings.items[last].len;
|
||||
if (offset < last_off + last_len) return .{ imsec.subsections.items[last], offset - last_off };
|
||||
if (offset < last_off + last_len) return .{
|
||||
.msub_index = imsec.subsections.items[last],
|
||||
.offset = offset - last_off,
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
|
||||
// Now, we are ready to resolve the symbols across all input files.
|
||||
// We will first resolve the files in the ZigObject, next in the parsed
|
||||
// input Object files.
|
||||
elf_file.resolveSymbols();
|
||||
try elf_file.resolveSymbols();
|
||||
elf_file.markEhFrameAtomsDead();
|
||||
try elf_file.resolveMergeSections();
|
||||
try elf_file.addCommentString();
|
||||
@@ -299,13 +299,16 @@ fn initSections(elf_file: *Elf) !void {
|
||||
} else false;
|
||||
if (needs_eh_frame) {
|
||||
elf_file.eh_frame_section_index = try elf_file.addSection(.{
|
||||
.name = ".eh_frame",
|
||||
.name = try elf_file.insertShString(".eh_frame"),
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.addralign = ptr_size,
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr(".rela.eh_frame", elf_file.eh_frame_section_index.?);
|
||||
elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr(
|
||||
try elf_file.insertShString(".rela.eh_frame"),
|
||||
elf_file.eh_frame_section_index.?,
|
||||
);
|
||||
}
|
||||
|
||||
try initComdatGroups(elf_file);
|
||||
@@ -318,22 +321,18 @@ fn initComdatGroups(elf_file: *Elf) !void {
|
||||
|
||||
for (elf_file.objects.items) |index| {
|
||||
const object = elf_file.file(index).?.object;
|
||||
|
||||
for (object.comdat_groups.items) |cg_index| {
|
||||
const cg = elf_file.comdatGroup(cg_index);
|
||||
const cg_owner = elf_file.comdatGroupOwner(cg.owner);
|
||||
if (cg_owner.file != index) continue;
|
||||
|
||||
for (object.comdat_groups.items, 0..) |cg, cg_index| {
|
||||
if (!cg.alive) continue;
|
||||
const cg_sec = try elf_file.comdat_group_sections.addOne(gpa);
|
||||
cg_sec.* = .{
|
||||
.shndx = try elf_file.addSection(.{
|
||||
.name = ".group",
|
||||
.name = try elf_file.insertShString(".group"),
|
||||
.type = elf.SHT_GROUP,
|
||||
.entsize = @sizeOf(u32),
|
||||
.addralign = @alignOf(u32),
|
||||
.offset = std.math.maxInt(u64),
|
||||
}),
|
||||
.cg_index = cg_index,
|
||||
.cg_ref = .{ .index = @intCast(cg_index), .file = index },
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -342,9 +341,9 @@ fn initComdatGroups(elf_file: *Elf) !void {
|
||||
fn updateSectionSizes(elf_file: *Elf) !void {
|
||||
for (elf_file.output_sections.keys(), elf_file.output_sections.values()) |shndx, atom_list| {
|
||||
const shdr = &elf_file.shdrs.items[shndx];
|
||||
for (atom_list.items) |atom_index| {
|
||||
const atom_ptr = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.flags.alive) continue;
|
||||
for (atom_list.items) |ref| {
|
||||
const atom_ptr = elf_file.atom(ref) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
const offset = atom_ptr.alignment.forward(shdr.sh_size);
|
||||
const padding = offset - shdr.sh_size;
|
||||
atom_ptr.value = @intCast(offset);
|
||||
@@ -355,9 +354,9 @@ fn updateSectionSizes(elf_file: *Elf) !void {
|
||||
|
||||
for (elf_file.output_rela_sections.values()) |sec| {
|
||||
const shdr = &elf_file.shdrs.items[sec.shndx];
|
||||
for (sec.atom_list.items) |atom_index| {
|
||||
const atom_ptr = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.flags.alive) continue;
|
||||
for (sec.atom_list.items) |ref| {
|
||||
const atom_ptr = elf_file.atom(ref) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
const relocs = atom_ptr.relocs(elf_file);
|
||||
shdr.sh_size += shdr.sh_entsize * relocs.len;
|
||||
}
|
||||
@@ -386,7 +385,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void {
|
||||
|
||||
const sym = elf_file.symbol(cg.symbol(elf_file));
|
||||
shdr.sh_info = sym.outputSymtabIndex(elf_file) orelse
|
||||
elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx().?);
|
||||
elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx(elf_file).?);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,16 +448,16 @@ fn writeAtoms(elf_file: *Elf) !void {
|
||||
0;
|
||||
@memset(buffer, padding_byte);
|
||||
|
||||
for (atom_list.items) |atom_index| {
|
||||
const atom_ptr = elf_file.atom(atom_index).?;
|
||||
assert(atom_ptr.flags.alive);
|
||||
for (atom_list.items) |ref| {
|
||||
const atom_ptr = elf_file.atom(ref).?;
|
||||
assert(atom_ptr.alive);
|
||||
|
||||
const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse
|
||||
return error.Overflow;
|
||||
const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
|
||||
|
||||
log.debug("writing atom({d}) from 0x{x} to 0x{x}", .{
|
||||
atom_index,
|
||||
log.debug("writing atom({}) from 0x{x} to 0x{x}", .{
|
||||
ref,
|
||||
sh_offset + offset,
|
||||
sh_offset + offset + size,
|
||||
});
|
||||
@@ -466,8 +465,8 @@ fn writeAtoms(elf_file: *Elf) !void {
|
||||
// TODO decompress directly into provided buffer
|
||||
const out_code = buffer[offset..][0..size];
|
||||
const in_code = switch (atom_ptr.file(elf_file).?) {
|
||||
.object => |x| try x.codeDecompressAlloc(elf_file, atom_index),
|
||||
.zig_object => |x| try x.codeAlloc(elf_file, atom_index),
|
||||
.object => |x| try x.codeDecompressAlloc(elf_file, ref.index),
|
||||
.zig_object => |x| try x.codeAlloc(elf_file, ref.index),
|
||||
else => unreachable,
|
||||
};
|
||||
defer gpa.free(in_code);
|
||||
@@ -491,9 +490,9 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
|
||||
var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs);
|
||||
defer relocs.deinit();
|
||||
|
||||
for (sec.atom_list.items) |atom_index| {
|
||||
const atom_ptr = elf_file.atom(atom_index) orelse continue;
|
||||
if (!atom_ptr.flags.alive) continue;
|
||||
for (sec.atom_list.items) |ref| {
|
||||
const atom_ptr = elf_file.atom(ref) orelse continue;
|
||||
if (!atom_ptr.alive) continue;
|
||||
try atom_ptr.writeRelocs(elf_file, &relocs);
|
||||
}
|
||||
assert(relocs.items.len == num_relocs);
|
||||
|
||||
@@ -1075,7 +1075,7 @@ pub const GotPltSection = struct {
|
||||
_ = got_plt;
|
||||
{
|
||||
// [0]: _DYNAMIC
|
||||
const symbol = elf_file.symbol(elf_file.dynamic_index.?);
|
||||
const symbol = elf_file.symbol(elf_file.linkerDefinedPtr().?.dynamic_index.?);
|
||||
try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little);
|
||||
}
|
||||
// [1]: 0x0
|
||||
@@ -1670,45 +1670,44 @@ pub const VerneedSection = struct {
|
||||
|
||||
pub const ComdatGroupSection = struct {
|
||||
shndx: u32,
|
||||
cg_index: u32,
|
||||
cg_ref: Elf.Ref,
|
||||
|
||||
fn file(cgs: ComdatGroupSection, elf_file: *Elf) ?File {
|
||||
const cg = elf_file.comdatGroup(cgs.cg_index);
|
||||
const cg_owner = elf_file.comdatGroupOwner(cg.owner);
|
||||
return elf_file.file(cg_owner.file);
|
||||
fn comdatGroup(cgs: ComdatGroupSection, elf_file: *Elf) *Elf.ComdatGroup {
|
||||
const cg_file = elf_file.file(cgs.cg_ref.file).?;
|
||||
return cg_file.object.comdatGroup(cgs.cg_ref.index);
|
||||
}
|
||||
|
||||
pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index {
|
||||
const cg = elf_file.comdatGroup(cgs.cg_index);
|
||||
const object = cgs.file(elf_file).?.object;
|
||||
const cg = cgs.comdatGroup(elf_file);
|
||||
const object = cg.file(elf_file).object;
|
||||
const shdr = object.shdrs.items[cg.shndx];
|
||||
return object.symbols.items[shdr.sh_info];
|
||||
}
|
||||
|
||||
pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize {
|
||||
const cg = elf_file.comdatGroup(cgs.cg_index);
|
||||
const cg = cgs.comdatGroup(elf_file);
|
||||
const members = cg.comdatGroupMembers(elf_file);
|
||||
return (members.len + 1) * @sizeOf(u32);
|
||||
}
|
||||
|
||||
pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void {
|
||||
const cg = elf_file.comdatGroup(cgs.cg_index);
|
||||
const object = cgs.file(elf_file).?.object;
|
||||
const cg = cgs.comdatGroup(elf_file);
|
||||
const object = cg.file(elf_file).object;
|
||||
const members = cg.comdatGroupMembers(elf_file);
|
||||
try writer.writeInt(u32, elf.GRP_COMDAT, .little);
|
||||
for (members) |shndx| {
|
||||
const shdr = object.shdrs.items[shndx];
|
||||
switch (shdr.sh_type) {
|
||||
elf.SHT_RELA => {
|
||||
const atom_index = object.atoms.items[shdr.sh_info];
|
||||
const atom = elf_file.atom(atom_index).?;
|
||||
const rela = elf_file.output_rela_sections.get(atom.outputShndx().?).?;
|
||||
const atom_index = object.atoms_indexes.items[shdr.sh_info];
|
||||
const atom = object.atom(atom_index).?;
|
||||
const rela = elf_file.output_rela_sections.get(atom.output_section_index).?;
|
||||
try writer.writeInt(u32, rela.shndx, .little);
|
||||
},
|
||||
else => {
|
||||
const atom_index = object.atoms.items[shndx];
|
||||
const atom = elf_file.atom(atom_index).?;
|
||||
try writer.writeInt(u32, atom.outputShndx().?, .little);
|
||||
const atom_index = object.atoms_indexes.items[shndx];
|
||||
const atom = object.atom(atom_index).?;
|
||||
try writer.writeInt(u32, atom.output_section_index, .little);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,22 +6,21 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
|
||||
const atoms = elf_file.output_sections.get(shndx).?.items;
|
||||
assert(atoms.len > 0);
|
||||
|
||||
for (atoms) |atom_index| {
|
||||
elf_file.atom(atom_index).?.value = -1;
|
||||
for (atoms) |ref| {
|
||||
elf_file.atom(ref).?.value = -1;
|
||||
}
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < atoms.len) {
|
||||
const start = i;
|
||||
const start_atom = elf_file.atom(atoms[start]).?;
|
||||
assert(start_atom.flags.alive);
|
||||
assert(start_atom.alive);
|
||||
start_atom.value = try advance(shdr, start_atom.size, start_atom.alignment);
|
||||
i += 1;
|
||||
|
||||
while (i < atoms.len) : (i += 1) {
|
||||
const atom_index = atoms[i];
|
||||
const atom = elf_file.atom(atom_index).?;
|
||||
assert(atom.flags.alive);
|
||||
const atom = elf_file.atom(atoms[i]).?;
|
||||
assert(atom.alive);
|
||||
if (@as(i64, @intCast(atom.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance)
|
||||
break;
|
||||
atom.value = try advance(shdr, atom.size, atom.alignment);
|
||||
@@ -33,10 +32,10 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
|
||||
thunk.output_section_index = shndx;
|
||||
|
||||
// Scan relocs in the group and create trampolines for any unreachable callsite
|
||||
for (atoms[start..i]) |atom_index| {
|
||||
const atom = elf_file.atom(atom_index).?;
|
||||
for (atoms[start..i]) |ref| {
|
||||
const atom = elf_file.atom(ref).?;
|
||||
const file = atom.file(elf_file).?;
|
||||
log.debug("atom({d}) {s}", .{ atom_index, atom.name(elf_file) });
|
||||
log.debug("atom({}) {s}", .{ ref, atom.name(elf_file) });
|
||||
for (atom.relocs(elf_file)) |rel| {
|
||||
const is_reachable = switch (cpu_arch) {
|
||||
.aarch64 => aarch64.isReachable(atom, rel, elf_file),
|
||||
@@ -51,8 +50,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
|
||||
};
|
||||
try thunk.symbols.put(gpa, target, {});
|
||||
}
|
||||
try atom.addExtra(.{ .thunk = thunk_index }, elf_file);
|
||||
atom.flags.thunk = true;
|
||||
atom.addExtra(.{ .thunk = thunk_index }, elf_file);
|
||||
}
|
||||
|
||||
thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));
|
||||
|
||||
@@ -45,8 +45,7 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void {
|
||||
|
||||
pub fn init(self: *InternalObject, allocator: Allocator) !void {
|
||||
// Atom at index 0 is reserved as null atom.
|
||||
try self.atoms.append(allocator, .{});
|
||||
try self.atoms_extra.append(allocator, 0);
|
||||
try self.atoms.append(allocator, .{ .extra = try self.addAtomExtra(allocator, .{}) });
|
||||
// Null byte in strtab
|
||||
try self.strtab.append(allocator, 0);
|
||||
}
|
||||
|
||||
@@ -1634,7 +1634,7 @@ fn isThreadlocal(macho_file: *MachO, decl_index: InternPool.DeclIndex) bool {
|
||||
|
||||
fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
|
||||
try self.atoms.ensureUnusedCapacity(allocator, 1);
|
||||
try self.atoms_extra.ensureUnusedCapacity(allocator, 1);
|
||||
try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
|
||||
return self.addAtomAssumeCapacity();
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
|
||||
// Exercise linker with LLVM backend
|
||||
// musl tests
|
||||
elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testComdatElimination(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target }));
|
||||
elf_step.dependOn(testCommentString(b, .{ .target = musl_target }));
|
||||
@@ -368,6 +369,109 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testComdatElimination(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "comdat-elimination", opts);
|
||||
|
||||
const a_o = addObject(b, opts, .{
|
||||
.name = "a",
|
||||
.cpp_source_bytes =
|
||||
\\#include <stdio.h>
|
||||
\\inline void foo() {
|
||||
\\ printf("calling foo in a\n");
|
||||
\\}
|
||||
\\void hello() {
|
||||
\\ foo();
|
||||
\\}
|
||||
,
|
||||
});
|
||||
a_o.linkLibCpp();
|
||||
|
||||
const main_o = addObject(b, opts, .{
|
||||
.name = "main",
|
||||
.cpp_source_bytes =
|
||||
\\#include <stdio.h>
|
||||
\\inline void foo() {
|
||||
\\ printf("calling foo in main\n");
|
||||
\\}
|
||||
\\void hello();
|
||||
\\int main() {
|
||||
\\ foo();
|
||||
\\ hello();
|
||||
\\ return 0;
|
||||
\\}
|
||||
,
|
||||
});
|
||||
main_o.linkLibCpp();
|
||||
|
||||
{
|
||||
const exe = addExecutable(b, opts, .{ .name = "main1" });
|
||||
exe.addObject(a_o);
|
||||
exe.addObject(main_o);
|
||||
exe.linkLibCpp();
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual(
|
||||
\\calling foo in a
|
||||
\\calling foo in a
|
||||
\\
|
||||
);
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
|
||||
{
|
||||
const exe = addExecutable(b, opts, .{ .name = "main2" });
|
||||
exe.addObject(main_o);
|
||||
exe.addObject(a_o);
|
||||
exe.linkLibCpp();
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual(
|
||||
\\calling foo in main
|
||||
\\calling foo in main
|
||||
\\
|
||||
);
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
|
||||
{
|
||||
const c_o = addObject(b, opts, .{ .name = "c" });
|
||||
c_o.addObject(main_o);
|
||||
c_o.addObject(a_o);
|
||||
|
||||
const exe = addExecutable(b, opts, .{ .name = "main3" });
|
||||
exe.addObject(c_o);
|
||||
exe.linkLibCpp();
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual(
|
||||
\\calling foo in main
|
||||
\\calling foo in main
|
||||
\\
|
||||
);
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
|
||||
{
|
||||
const d_o = addObject(b, opts, .{ .name = "d" });
|
||||
d_o.addObject(a_o);
|
||||
d_o.addObject(main_o);
|
||||
|
||||
const exe = addExecutable(b, opts, .{ .name = "main4" });
|
||||
exe.addObject(d_o);
|
||||
exe.linkLibCpp();
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual(
|
||||
\\calling foo in a
|
||||
\\calling foo in a
|
||||
\\
|
||||
);
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testCommentString(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "comment-string", opts);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user