Merge pull request #21629 from ziglang/elf-incr

elf: more incremental progress
This commit is contained in:
Andrew Kelley 2024-10-09 17:43:17 -07:00 committed by GitHub
commit 2e2927735d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 383 additions and 413 deletions

View File

@ -389,15 +389,10 @@ pub const Section = struct {
if (dwarf.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
const atom = zo.symbol(sec.index).atom(elf_file).?;
const shndx = atom.output_section_index;
if (sec == &dwarf.debug_frame.section)
try elf_file.growAllocSection(shndx, len, sec.alignment.toByteUnits().?)
else
try elf_file.growNonAllocSection(shndx, len, sec.alignment.toByteUnits().?, true);
const shdr = elf_file.sections.items(.shdr)[shndx];
atom.size = shdr.sh_size;
atom.alignment = InternPool.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
sec.len = shdr.sh_size;
atom.size = len;
atom.alignment = sec.alignment;
sec.len = len;
try zo.allocateAtom(atom, false, elf_file);
} else if (dwarf.bin_file.cast(.macho)) |macho_file| {
const header = if (macho_file.d_sym) |*d_sym| header: {
try d_sym.growSection(@intCast(sec.index), len, true, macho_file);
@ -418,11 +413,15 @@ pub const Section = struct {
if (dwarf.bin_file.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
const atom = zo.symbol(sec.index).atom(elf_file).?;
const shndx = atom.output_section_index;
const shdr = &elf_file.sections.items(.shdr)[shndx];
atom.size = sec.len;
shdr.sh_offset += len;
shdr.sh_size = sec.len;
if (atom.prevAtom(elf_file)) |_| {
// FIXME:JK trimming/shrinking has to be reworked on ZigObject/Elf level
atom.value += len;
} else {
const shdr = &elf_file.sections.items(.shdr)[atom.output_section_index];
shdr.sh_offset += len;
atom.value = 0;
}
atom.size -= len;
} else if (dwarf.bin_file.cast(.macho)) |macho_file| {
const header = if (macho_file.d_sym) |*d_sym|
&d_sym.sections.items[sec.index]
@ -911,11 +910,9 @@ const Entry = struct {
if (std.debug.runtime_safety) {
log.err("missing {} from {s}", .{
@as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)),
std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file| sh_name: {
const zo = elf_file.zigObjectPtr().?;
const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index;
break :sh_name elf_file.shstrtab.items[elf_file.sections.items(.shdr)[shndx].sh_name..];
} else if (dwarf.bin_file.cast(.macho)) |macho_file|
std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file|
elf_file.zigObjectPtr().?.symbol(sec.index).name(elf_file)
else if (dwarf.bin_file.cast(.macho)) |macho_file|
if (macho_file.d_sym) |*d_sym|
&d_sym.sections.items[sec.index].segname
else

View File

@ -548,16 +548,6 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
return min_pos - start;
}
fn allocatedVirtualSize(self: *Elf, start: u64) u64 {
if (start == 0) return 0;
var min_pos: u64 = std.math.maxInt(u64);
for (self.phdrs.items) |phdr| {
if (phdr.p_vaddr <= start) continue;
if (phdr.p_vaddr < min_pos) min_pos = phdr.p_vaddr;
}
return min_pos - start;
}
pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 {
var start: u64 = 0;
while (try self.detectAllocCollision(start, object_size)) |item_end| {
@ -566,90 +556,49 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 {
return start;
}
pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment: u64) !void {
const slice = self.sections.slice();
const shdr = &slice.items(.shdr)[shdr_index];
assert(shdr.sh_flags & elf.SHF_ALLOC != 0);
const phndx = slice.items(.phndx)[shdr_index];
const maybe_phdr = if (phndx) |ndx| &self.phdrs.items[ndx] else null;
log.debug("allocated size {x} of {s}, needed size {x}", .{
self.allocatedSize(shdr.sh_offset),
self.getShString(shdr.sh_name),
needed_size,
});
pub fn growSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment: u64) !void {
const shdr = &self.sections.items(.shdr)[shdr_index];
if (shdr.sh_type != elf.SHT_NOBITS) {
const allocated_size = self.allocatedSize(shdr.sh_offset);
log.debug("allocated size {x} of '{s}', needed size {x}", .{
allocated_size,
self.getShString(shdr.sh_name),
needed_size,
});
if (needed_size > allocated_size) {
const existing_size = shdr.sh_size;
shdr.sh_size = 0;
// Must move the entire section.
const new_offset = try self.findFreeSpace(needed_size, min_alignment);
log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
log.debug("moving '{s}' from 0x{x} to 0x{x}", .{
self.getShString(shdr.sh_name),
shdr.sh_offset,
new_offset,
new_offset + existing_size,
});
const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size);
// TODO figure out what to about this error condition - how to communicate it up.
if (amt != existing_size) return error.InputOutput;
shdr.sh_offset = new_offset;
if (maybe_phdr) |phdr| phdr.p_offset = new_offset;
} else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
}
if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;
}
shdr.sh_size = needed_size;
self.markDirty(shdr_index);
}
pub fn growNonAllocSection(
self: *Elf,
shdr_index: u32,
needed_size: u64,
min_alignment: u64,
requires_file_copy: bool,
) !void {
const shdr = &self.sections.items(.shdr)[shdr_index];
assert(shdr.sh_flags & elf.SHF_ALLOC == 0);
const allocated_size = self.allocatedSize(shdr.sh_offset);
if (needed_size > allocated_size) {
const existing_size = shdr.sh_size;
shdr.sh_size = 0;
// Move all the symbols to a new file location.
const new_offset = try self.findFreeSpace(needed_size, min_alignment);
log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
self.getShString(shdr.sh_name),
new_offset,
new_offset + existing_size,
});
if (requires_file_copy) {
const amt = try self.base.file.?.copyRangeAll(
shdr.sh_offset,
self.base.file.?,
new_offset,
existing_size,
);
// TODO figure out what to about this error condition - how to communicate it up.
if (amt != existing_size) return error.InputOutput;
}
shdr.sh_offset = new_offset;
} else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
shdr.sh_offset = new_offset;
} else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
}
}
shdr.sh_size = needed_size;
self.markDirty(shdr_index);
}
pub fn markDirty(self: *Elf, shdr_index: u32) void {
fn markDirty(self: *Elf, shdr_index: u32) void {
if (self.zigObjectPtr()) |zo| {
for ([_]?Symbol.Index{
zo.debug_info_index,
@ -742,25 +691,27 @@ pub fn allocateChunk(self: *Elf, args: struct {
}
};
log.debug("allocated chunk (size({x}),align({x})) at 0x{x} (file(0x{x}))", .{
args.size,
args.alignment.toByteUnits().?,
shdr.sh_addr + res.value,
shdr.sh_offset + res.value,
});
const expand_section = if (self.atom(res.placement)) |placement_atom|
placement_atom.nextAtom(self) == null
else
true;
if (expand_section) {
const needed_size = res.value + args.size;
if (shdr.sh_flags & elf.SHF_ALLOC != 0)
try self.growAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?)
else
try self.growNonAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?, true);
try self.growSection(args.shndx, needed_size, args.alignment.toByteUnits().?);
}
log.debug("allocated chunk (size({x}),align({x})) in {s} at 0x{x} (file(0x{x}))", .{
args.size,
args.alignment.toByteUnits().?,
self.getShString(shdr.sh_name),
shdr.sh_addr + res.value,
shdr.sh_offset + res.value,
});
log.debug(" placement {}, {s}", .{
res.placement,
if (self.atom(res.placement)) |atom_ptr| atom_ptr.name(self) else "",
});
return res;
}
@ -809,8 +760,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
const csu = try CsuObjects.init(arena, comp);
// Here we will parse object and library files (if referenced).
// csu prelude
if (csu.crt0) |path| try parseObjectReportingFailure(self, path);
if (csu.crti) |path| try parseObjectReportingFailure(self, path);
@ -1040,6 +989,13 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
// Beyond this point, everything has been allocated a virtual address and we can resolve
// the relocations, and commit objects to file.
for (self.objects.items) |index| {
self.file(index).?.object.dirty = false;
}
// TODO: would state tracking be more appropriate here? perhaps even custom relocation type?
self.rela_dyn.clearRetainingCapacity();
self.rela_plt.clearRetainingCapacity();
if (self.zigObjectPtr()) |zo| {
var has_reloc_errors = false;
for (zo.atoms_indexes.items) |atom_index| {
@ -1069,6 +1025,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
try self.writeShdrTable();
try self.writeAtoms();
try self.writeMergeSections();
self.writeSyntheticSections() catch |err| switch (err) {
error.RelocFailure => return error.FlushFailure,
error.UnsupportedCpuArch => {
@ -1401,7 +1358,6 @@ pub fn parseLibraryReportingFailure(self: *Elf, lib: SystemLib, must_link: bool)
fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
const tracy = trace(@src());
defer tracy.end();
if (try Archive.isArchive(lib.path)) {
try self.parseArchive(lib.path, must_link);
} else if (try SharedObject.isSharedObject(lib.path)) {
@ -2801,9 +2757,10 @@ pub fn resolveMergeSections(self: *Elf) !void {
var has_errors = false;
for (self.objects.items) |index| {
const file_ptr = self.file(index).?;
if (!file_ptr.isAlive()) continue;
file_ptr.object.initInputMergeSections(self) catch |err| switch (err) {
const object = self.file(index).?.object;
if (!object.alive) continue;
if (!object.dirty) continue;
object.initInputMergeSections(self) catch |err| switch (err) {
error.LinkFailure => has_errors = true,
else => |e| return e,
};
@ -2812,15 +2769,17 @@ pub fn resolveMergeSections(self: *Elf) !void {
if (has_errors) return error.FlushFailure;
for (self.objects.items) |index| {
const file_ptr = self.file(index).?;
if (!file_ptr.isAlive()) continue;
try file_ptr.object.initOutputMergeSections(self);
const object = self.file(index).?.object;
if (!object.alive) continue;
if (!object.dirty) continue;
try object.initOutputMergeSections(self);
}
for (self.objects.items) |index| {
const file_ptr = self.file(index).?;
if (!file_ptr.isAlive()) continue;
file_ptr.object.resolveMergeSubsections(self) catch |err| switch (err) {
const object = self.file(index).?.object;
if (!object.alive) continue;
if (!object.dirty) continue;
object.resolveMergeSubsections(self) catch |err| switch (err) {
error.LinkFailure => has_errors = true,
else => |e| return e,
};
@ -2907,7 +2866,6 @@ fn initSyntheticSections(self: *Elf) !void {
elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC,
.addralign = ptr_size,
.offset = std.math.maxInt(u64),
});
}
if (comp.link_eh_frame_hdr and self.eh_frame_hdr_section_index == null) {
@ -2916,7 +2874,6 @@ fn initSyntheticSections(self: *Elf) !void {
.type = elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC,
.addralign = 4,
.offset = std.math.maxInt(u64),
});
}
}
@ -2927,7 +2884,6 @@ fn initSyntheticSections(self: *Elf) !void {
.type = elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
.addralign = ptr_size,
.offset = std.math.maxInt(u64),
});
}
@ -2937,7 +2893,6 @@ fn initSyntheticSections(self: *Elf) !void {
.type = elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
.addralign = @alignOf(u64),
.offset = std.math.maxInt(u64),
});
}
@ -2959,7 +2914,6 @@ fn initSyntheticSections(self: *Elf) !void {
.flags = elf.SHF_ALLOC,
.addralign = @alignOf(elf.Elf64_Rela),
.entsize = @sizeOf(elf.Elf64_Rela),
.offset = std.math.maxInt(u64),
});
}
@ -2970,7 +2924,6 @@ fn initSyntheticSections(self: *Elf) !void {
.type = elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
.addralign = 16,
.offset = std.math.maxInt(u64),
});
}
if (self.rela_plt_section_index == null) {
@ -2980,7 +2933,6 @@ fn initSyntheticSections(self: *Elf) !void {
.flags = elf.SHF_ALLOC,
.addralign = @alignOf(elf.Elf64_Rela),
.entsize = @sizeOf(elf.Elf64_Rela),
.offset = std.math.maxInt(u64),
});
}
}
@ -2991,7 +2943,6 @@ fn initSyntheticSections(self: *Elf) !void {
.type = elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
.addralign = 16,
.offset = std.math.maxInt(u64),
});
}
@ -3000,7 +2951,6 @@ fn initSyntheticSections(self: *Elf) !void {
.name = try self.insertShString(".copyrel"),
.type = elf.SHT_NOBITS,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
.offset = std.math.maxInt(u64),
});
}
@ -3019,7 +2969,6 @@ fn initSyntheticSections(self: *Elf) !void {
.type = elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC,
.addralign = 1,
.offset = std.math.maxInt(u64),
});
}
@ -3031,7 +2980,6 @@ fn initSyntheticSections(self: *Elf) !void {
.type = elf.SHT_STRTAB,
.entsize = 1,
.addralign = 1,
.offset = std.math.maxInt(u64),
});
}
if (self.dynamic_section_index == null) {
@ -3041,7 +2989,6 @@ fn initSyntheticSections(self: *Elf) !void {
.type = elf.SHT_DYNAMIC,
.entsize = @sizeOf(elf.Elf64_Dyn),
.addralign = @alignOf(elf.Elf64_Dyn),
.offset = std.math.maxInt(u64),
});
}
if (self.dynsymtab_section_index == null) {
@ -3052,7 +2999,6 @@ fn initSyntheticSections(self: *Elf) !void {
.addralign = @alignOf(elf.Elf64_Sym),
.entsize = @sizeOf(elf.Elf64_Sym),
.info = 1,
.offset = std.math.maxInt(u64),
});
}
if (self.hash_section_index == null) {
@ -3062,7 +3008,6 @@ fn initSyntheticSections(self: *Elf) !void {
.type = elf.SHT_HASH,
.addralign = 4,
.entsize = 4,
.offset = std.math.maxInt(u64),
});
}
if (self.gnu_hash_section_index == null) {
@ -3071,7 +3016,6 @@ fn initSyntheticSections(self: *Elf) !void {
.flags = elf.SHF_ALLOC,
.type = elf.SHT_GNU_HASH,
.addralign = 8,
.offset = std.math.maxInt(u64),
});
}
@ -3087,7 +3031,6 @@ fn initSyntheticSections(self: *Elf) !void {
.type = elf.SHT_GNU_VERSYM,
.addralign = @alignOf(elf.Elf64_Versym),
.entsize = @sizeOf(elf.Elf64_Versym),
.offset = std.math.maxInt(u64),
});
}
if (self.verneed_section_index == null) {
@ -3096,7 +3039,6 @@ fn initSyntheticSections(self: *Elf) !void {
.flags = elf.SHF_ALLOC,
.type = elf.SHT_GNU_VERNEED,
.addralign = @alignOf(elf.Elf64_Verneed),
.offset = std.math.maxInt(u64),
});
}
}
@ -3117,7 +3059,6 @@ pub fn initSymtab(self: *Elf) !void {
.type = elf.SHT_SYMTAB,
.addralign = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym),
.entsize = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym),
.offset = std.math.maxInt(u64),
});
}
if (self.strtab_section_index == null) {
@ -3126,7 +3067,6 @@ pub fn initSymtab(self: *Elf) !void {
.type = elf.SHT_STRTAB,
.entsize = 1,
.addralign = 1,
.offset = std.math.maxInt(u64),
});
}
}
@ -3138,7 +3078,6 @@ pub fn initShStrtab(self: *Elf) !void {
.type = elf.SHT_STRTAB,
.entsize = 1,
.addralign = 1,
.offset = std.math.maxInt(u64),
});
}
}
@ -3219,7 +3158,7 @@ fn sortInitFini(self: *Elf) !void {
for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
if (atom_list.atoms.items.len == 0) continue;
if (atom_list.atoms.keys().len == 0) continue;
var is_init_fini = false;
var is_ctor_dtor = false;
@ -3236,10 +3175,10 @@ fn sortInitFini(self: *Elf) !void {
if (!is_init_fini and !is_ctor_dtor) continue;
var entries = std.ArrayList(Entry).init(gpa);
try entries.ensureTotalCapacityPrecise(atom_list.atoms.items.len);
try entries.ensureTotalCapacityPrecise(atom_list.atoms.keys().len);
defer entries.deinit();
for (atom_list.atoms.items) |ref| {
for (atom_list.atoms.keys()) |ref| {
const atom_ptr = self.atom(ref).?;
const object = atom_ptr.file(self).?.object;
const priority = blk: {
@ -3260,7 +3199,7 @@ fn sortInitFini(self: *Elf) !void {
atom_list.atoms.clearRetainingCapacity();
for (entries.items) |entry| {
atom_list.atoms.appendAssumeCapacity(entry.atom_ref);
_ = atom_list.atoms.getOrPutAssumeCapacity(entry.atom_ref);
}
}
}
@ -3506,7 +3445,7 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
const slice = self.sections.slice();
for (slice.items(.shdr), slice.items(.atom_list_2)) |*shdr, *atom_list| {
atom_list.output_section_index = backlinks[atom_list.output_section_index];
for (atom_list.atoms.items) |ref| {
for (atom_list.atoms.keys()) |ref| {
self.atom(ref).?.output_section_index = atom_list.output_section_index;
}
if (shdr.sh_type == elf.SHT_RELA) {
@ -3518,12 +3457,7 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
}
}
if (self.zigObjectPtr()) |zo| {
for (zo.atoms_indexes.items) |atom_index| {
const atom_ptr = zo.atom(atom_index) orelse continue;
atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
}
}
if (self.zigObjectPtr()) |zo| zo.resetShdrIndexes(backlinks);
for (self.comdat_group_sections.items) |*cg| {
cg.shndx = backlinks[cg.shndx];
@ -3585,20 +3519,24 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
fn updateSectionSizes(self: *Elf) !void {
const slice = self.sections.slice();
for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
if (atom_list.atoms.items.len == 0) continue;
if (atom_list.atoms.keys().len == 0) continue;
if (!atom_list.dirty) continue;
if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue;
atom_list.updateSize(self);
try atom_list.allocate(self);
atom_list.dirty = false;
}
if (self.requiresThunks()) {
for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| {
if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue;
if (atom_list.atoms.items.len == 0) continue;
if (atom_list.atoms.keys().len == 0) continue;
if (!atom_list.dirty) continue;
// Create jump/branch range extenders if needed.
try self.createThunks(atom_list);
try atom_list.allocate(self);
atom_list.dirty = false;
}
// FIXME:JK this will hopefully not be needed once we create a link from Atom/Thunk to AtomList.
@ -3882,57 +3820,55 @@ pub fn allocateAllocSections(self: *Elf) !void {
}
const first = slice.items(.shdr)[cover.items[0]];
var new_offset = try self.findFreeSpace(filesz, @"align");
const phndx = self.getPhdr(.{ .type = elf.PT_LOAD, .flags = shdrToPhdrFlags(first.sh_flags) }).?;
const phdr = &self.phdrs.items[phndx];
phdr.p_offset = new_offset;
phdr.p_vaddr = first.sh_addr;
phdr.p_paddr = first.sh_addr;
phdr.p_memsz = memsz;
phdr.p_filesz = filesz;
phdr.p_align = @"align";
const allocated_size = self.allocatedSize(phdr.p_offset);
if (filesz > allocated_size) {
const old_offset = phdr.p_offset;
phdr.p_offset = 0;
var new_offset = try self.findFreeSpace(filesz, @"align");
phdr.p_offset = new_offset;
for (cover.items) |shndx| {
const shdr = &slice.items(.shdr)[shndx];
slice.items(.phndx)[shndx] = phndx;
if (shdr.sh_type == elf.SHT_NOBITS) {
shdr.sh_offset = 0;
continue;
}
new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset);
log.debug("moving phdr({d}) from 0x{x} to 0x{x}", .{ phndx, old_offset, new_offset });
for (cover.items) |shndx| {
const shdr = &slice.items(.shdr)[shndx];
slice.items(.phndx)[shndx] = phndx;
if (shdr.sh_type == elf.SHT_NOBITS) {
shdr.sh_offset = 0;
continue;
}
new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset);
if (self.zigObjectPtr()) |zo| blk: {
const existing_size = for ([_]?Symbol.Index{
zo.text_index,
zo.rodata_index,
zo.data_relro_index,
zo.data_index,
zo.tdata_index,
zo.eh_frame_index,
}) |maybe_sym_index| {
const sect_sym_index = maybe_sym_index orelse continue;
const sect_atom_ptr = zo.symbol(sect_sym_index).atom(self).?;
if (sect_atom_ptr.output_section_index != shndx) continue;
break sect_atom_ptr.size;
} else break :blk;
log.debug("moving {s} from 0x{x} to 0x{x}", .{
self.getShString(shdr.sh_name),
shdr.sh_offset,
new_offset,
});
const amt = try self.base.file.?.copyRangeAll(
shdr.sh_offset,
self.base.file.?,
new_offset,
existing_size,
);
if (amt != existing_size) return error.InputOutput;
}
shdr.sh_offset = new_offset;
new_offset += shdr.sh_size;
if (shdr.sh_offset > 0) {
// Get size actually commited to the output file.
const existing_size = self.sectionSize(shndx);
const amt = try self.base.file.?.copyRangeAll(
shdr.sh_offset,
self.base.file.?,
new_offset,
existing_size,
);
if (amt != existing_size) return error.InputOutput;
}
shdr.sh_offset = new_offset;
new_offset += shdr.sh_size;
}
}
phdr.p_vaddr = first.sh_addr;
phdr.p_paddr = first.sh_addr;
phdr.p_memsz = memsz;
phdr.p_filesz = filesz;
phdr.p_align = @"align";
addr = mem.alignForward(u64, addr, self.page_size);
}
}
@ -3947,27 +3883,14 @@ pub fn allocateNonAllocSections(self: *Elf) !void {
shdr.sh_size = 0;
const new_offset = try self.findFreeSpace(needed_size, shdr.sh_addralign);
if (self.zigObjectPtr()) |zo| blk: {
const existing_size = for ([_]?Symbol.Index{
zo.debug_info_index,
zo.debug_abbrev_index,
zo.debug_aranges_index,
zo.debug_str_index,
zo.debug_line_index,
zo.debug_line_str_index,
zo.debug_loclists_index,
zo.debug_rnglists_index,
}) |maybe_sym_index| {
const sym_index = maybe_sym_index orelse continue;
const sym = zo.symbol(sym_index);
const atom_ptr = sym.atom(self).?;
if (atom_ptr.output_section_index == shndx) break atom_ptr.size;
} else break :blk;
log.debug("moving {s} from 0x{x} to 0x{x}", .{
self.getShString(shdr.sh_name),
shdr.sh_offset,
new_offset,
});
log.debug("moving {s} from 0x{x} to 0x{x}", .{
self.getShString(shdr.sh_name),
shdr.sh_offset,
new_offset,
});
if (shdr.sh_offset > 0) {
const existing_size = self.sectionSize(@intCast(shndx));
const amt = try self.base.file.?.copyRangeAll(
shdr.sh_offset,
self.base.file.?,
@ -4058,7 +3981,7 @@ fn writeAtoms(self: *Elf) !void {
var has_reloc_errors = false;
for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| {
if (shdr.sh_type == elf.SHT_NOBITS) continue;
if (atom_list.atoms.items.len == 0) continue;
if (atom_list.atoms.keys().len == 0) continue;
atom_list.write(&buffer, &undefs, self) catch |err| switch (err) {
error.UnsupportedCpuArch => {
try self.reportUnsupportedCpuArch();
@ -4816,7 +4739,6 @@ pub fn addRelaShdr(self: *Elf, name: u32, shndx: u32) !u32 {
.entsize = entsize,
.info = shndx,
.addralign = addralign,
.offset = std.math.maxInt(u64),
});
}
@ -4828,7 +4750,6 @@ pub const AddSectionOpts = struct {
info: u32 = 0,
addralign: u64 = 0,
entsize: u64 = 0,
offset: u64 = 0,
};
pub fn addSection(self: *Elf, opts: AddSectionOpts) !u32 {
@ -4840,7 +4761,7 @@ pub fn addSection(self: *Elf, opts: AddSectionOpts) !u32 {
.sh_type = opts.type,
.sh_flags = opts.flags,
.sh_addr = 0,
.sh_offset = opts.offset,
.sh_offset = 0,
.sh_size = 0,
.sh_link = opts.link,
.sh_info = opts.info,
@ -4863,6 +4784,7 @@ const RelaDyn = struct {
sym: u64 = 0,
type: u32,
addend: i64 = 0,
target: ?*const Symbol = null,
};
pub fn addRelaDyn(self: *Elf, opts: RelaDyn) !void {
@ -4871,6 +4793,13 @@ pub fn addRelaDyn(self: *Elf, opts: RelaDyn) !void {
}
pub fn addRelaDynAssumeCapacity(self: *Elf, opts: RelaDyn) void {
relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{
relocation.fmtRelocType(opts.type, self.getTarget().cpu.arch),
opts.offset,
opts.sym,
if (opts.target) |sym| sym.name(self) else "",
opts.addend,
});
self.rela_dyn.appendAssumeCapacity(.{
.r_offset = opts.offset,
.r_info = (opts.sym << 32) | opts.type,
@ -5703,6 +5632,12 @@ const Section = struct {
free_list: std.ArrayListUnmanaged(Ref) = .empty,
};
pub fn sectionSize(self: *Elf, shndx: u32) u64 {
const last_atom_ref = self.sections.items(.last_atom)[shndx];
const atom_ptr = self.atom(last_atom_ref) orelse return 0;
return @as(u64, @intCast(atom_ptr.value)) + atom_ptr.size;
}
fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
return switch (cpu_arch) {
.mips, .mipsel, .mips64, .mips64el => "__start",
@ -5732,20 +5667,20 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
}
}.advance;
for (atom_list.atoms.items) |ref| {
for (atom_list.atoms.keys()) |ref| {
elf_file.atom(ref).?.value = -1;
}
var i: usize = 0;
while (i < atom_list.atoms.items.len) {
while (i < atom_list.atoms.keys().len) {
const start = i;
const start_atom = elf_file.atom(atom_list.atoms.items[start]).?;
const start_atom = elf_file.atom(atom_list.atoms.keys()[start]).?;
assert(start_atom.alive);
start_atom.value = try advance(atom_list, start_atom.size, start_atom.alignment);
i += 1;
while (i < atom_list.atoms.items.len) : (i += 1) {
const atom_ptr = elf_file.atom(atom_list.atoms.items[i]).?;
while (i < atom_list.atoms.keys().len) : (i += 1) {
const atom_ptr = elf_file.atom(atom_list.atoms.keys()[i]).?;
assert(atom_ptr.alive);
if (@as(i64, @intCast(atom_ptr.alignment.forward(atom_list.size))) - start_atom.value >= max_distance)
break;
@ -5758,7 +5693,7 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void {
thunk_ptr.output_section_index = atom_list.output_section_index;
// Scan relocs in the group and create trampolines for any unreachable callsite
for (atom_list.atoms.items[start..i]) |ref| {
for (atom_list.atoms.keys()[start..i]) |ref| {
const atom_ptr = elf_file.atom(ref).?;
const file_ptr = atom_ptr.file(elf_file).?;
log.debug("atom({}) {s}", .{ ref, atom_ptr.name(elf_file) });
@ -5801,6 +5736,7 @@ const assert = std.debug.assert;
const elf = std.elf;
const fs = std.fs;
const log = std.log.scoped(.link);
const relocs_log = std.log.scoped(.link_relocs);
const state_log = std.log.scoped(.link_state);
const math = std.math;
const mem = std.mem;

View File

@ -118,10 +118,19 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
return @intCast(next_addr - self.address(elf_file));
}
pub fn fileCapacity(self: Atom, elf_file: *Elf) u64 {
const self_off = self.offset(elf_file);
const next_off = if (self.nextAtom(elf_file)) |next_atom|
next_atom.offset(elf_file)
else
self_off + elf_file.allocatedSize(self_off);
return @intCast(next_off - self_off);
}
pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
// No need to keep a free list node for the last block.
const next = self.nextAtom(elf_file) orelse return false;
const cap: u64 = @intCast(next.address(elf_file) - self.address(elf_file));
const cap: u64 = @intCast(next.value - self.value);
const ideal_cap = Elf.padToIdeal(self.size);
if (cap <= ideal_cap) return false;
const surplus = cap - ideal_cap;
@ -723,6 +732,7 @@ fn resolveDynAbsReloc(
.sym = target.extra(elf_file).dynamic,
.type = relocation.encode(.abs, cpu_arch),
.addend = A,
.target = target,
});
try applyDynamicReloc(A, elf_file, writer);
} else {
@ -737,6 +747,7 @@ fn resolveDynAbsReloc(
.sym = target.extra(elf_file).dynamic,
.type = relocation.encode(.abs, cpu_arch),
.addend = A,
.target = target,
});
try applyDynamicReloc(A, elf_file, writer);
} else {
@ -750,6 +761,7 @@ fn resolveDynAbsReloc(
.sym = target.extra(elf_file).dynamic,
.type = relocation.encode(.abs, cpu_arch),
.addend = A,
.target = target,
});
try applyDynamicReloc(A, elf_file, writer);
},
@ -759,6 +771,7 @@ fn resolveDynAbsReloc(
.offset = P,
.type = relocation.encode(.rel, cpu_arch),
.addend = S + A,
.target = target,
});
try applyDynamicReloc(S + A, elf_file, writer);
},
@ -769,6 +782,7 @@ fn resolveDynAbsReloc(
.offset = P,
.type = relocation.encode(.irel, cpu_arch),
.addend = S_ + A,
.target = target,
});
try applyDynamicReloc(S_ + A, elf_file, writer);
},
@ -922,9 +936,10 @@ fn format2(
_ = unused_fmt_string;
const atom = ctx.atom;
const elf_file = ctx.elf_file;
try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x})", .{
try writer.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x}) : prev({}) : next({})", .{
atom.atom_index, atom.name(elf_file), atom.address(elf_file),
atom.output_section_index, atom.alignment.toByteUnits() orelse 0, atom.size,
atom.prev_atom_ref, atom.next_atom_ref,
});
if (atom.fdes(elf_file).len > 0) {
try writer.writeAll(" : fdes{ ");

View File

@ -2,7 +2,10 @@ value: i64 = 0,
size: u64 = 0,
alignment: Atom.Alignment = .@"1",
output_section_index: u32 = 0,
atoms: std.ArrayListUnmanaged(Elf.Ref) = .empty,
// atoms: std.ArrayListUnmanaged(Elf.Ref) = .empty,
atoms: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .empty,
dirty: bool = true,
pub fn deinit(list: *AtomList, allocator: Allocator) void {
list.atoms.deinit(allocator);
@ -19,10 +22,8 @@ pub fn offset(list: AtomList, elf_file: *Elf) u64 {
}
pub fn updateSize(list: *AtomList, elf_file: *Elf) void {
// TODO perhaps a 'stale' flag would be better here?
list.size = 0;
list.alignment = .@"1";
for (list.atoms.items) |ref| {
assert(list.dirty);
for (list.atoms.keys()) |ref| {
const atom_ptr = elf_file.atom(ref).?;
assert(atom_ptr.alive);
const off = atom_ptr.alignment.forward(list.size);
@ -34,6 +35,8 @@ pub fn updateSize(list: *AtomList, elf_file: *Elf) void {
}
pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
assert(list.dirty);
const alloc_res = try elf_file.allocateChunk(.{
.shndx = list.output_section_index,
.size = list.size,
@ -42,6 +45,8 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
});
list.value = @intCast(alloc_res.value);
log.debug("allocated atom_list({d}) at 0x{x}", .{ list.output_section_index, list.address(elf_file) });
const slice = elf_file.sections.slice();
const shdr = &slice.items(.shdr)[list.output_section_index];
const last_atom_ref = &slice.items(.last_atom)[list.output_section_index];
@ -56,13 +61,13 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
// FIXME:JK this currently ignores Thunks as valid chunks.
{
var idx: usize = 0;
while (idx < list.atoms.items.len) : (idx += 1) {
const curr_atom_ptr = elf_file.atom(list.atoms.items[idx]).?;
while (idx < list.atoms.keys().len) : (idx += 1) {
const curr_atom_ptr = elf_file.atom(list.atoms.keys()[idx]).?;
if (idx > 0) {
curr_atom_ptr.prev_atom_ref = list.atoms.items[idx - 1];
curr_atom_ptr.prev_atom_ref = list.atoms.keys()[idx - 1];
}
if (idx + 1 < list.atoms.items.len) {
curr_atom_ptr.next_atom_ref = list.atoms.items[idx + 1];
if (idx + 1 < list.atoms.keys().len) {
curr_atom_ptr.next_atom_ref = list.atoms.keys()[idx + 1];
}
}
}
@ -74,17 +79,20 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
}
// FIXME:JK if we had a link from Atom to parent AtomList we would not need to update Atom's value or osec index
for (list.atoms.items) |ref| {
for (list.atoms.keys()) |ref| {
const atom_ptr = elf_file.atom(ref).?;
atom_ptr.output_section_index = list.output_section_index;
atom_ptr.value += list.value;
}
list.dirty = false;
}
pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
const osec = elf_file.sections.items(.shdr)[list.output_section_index];
assert(osec.sh_type != elf.SHT_NOBITS);
assert(!list.dirty);
log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)});
@ -92,7 +100,7 @@ pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_fi
try buffer.ensureUnusedCapacity(list_size);
buffer.appendNTimesAssumeCapacity(0, list_size);
for (list.atoms.items) |ref| {
for (list.atoms.keys()) |ref| {
const atom_ptr = elf_file.atom(ref).?;
assert(atom_ptr.alive);
@ -128,7 +136,7 @@ pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *E
try buffer.ensureUnusedCapacity(list_size);
buffer.appendNTimesAssumeCapacity(0, list_size);
for (list.atoms.items) |ref| {
for (list.atoms.keys()) |ref| {
const atom_ptr = elf_file.atom(ref).?;
assert(atom_ptr.alive);
@ -149,13 +157,13 @@ pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *E
}
pub fn firstAtom(list: AtomList, elf_file: *Elf) *Atom {
assert(list.atoms.items.len > 0);
return elf_file.atom(list.atoms.items[0]).?;
assert(list.atoms.keys().len > 0);
return elf_file.atom(list.atoms.keys()[0]).?;
}
pub fn lastAtom(list: AtomList, elf_file: *Elf) *Atom {
assert(list.atoms.items.len > 0);
return elf_file.atom(list.atoms.items[list.atoms.items.len - 1]).?;
assert(list.atoms.keys().len > 0);
return elf_file.atom(list.atoms.keys()[list.atoms.keys().len - 1]).?;
}
pub fn format(
@ -191,9 +199,9 @@ fn format2(
list.alignment.toByteUnits() orelse 0, list.size,
});
try writer.writeAll(" : atoms{ ");
for (list.atoms.items, 0..) |ref, i| {
for (list.atoms.keys(), 0..) |ref, i| {
try writer.print("{}", .{ref});
if (i < list.atoms.items.len - 1) try writer.writeAll(", ");
if (i < list.atoms.keys().len - 1) try writer.writeAll(", ");
}
try writer.writeAll(" }");
}

View File

@ -29,6 +29,7 @@ cies: std.ArrayListUnmanaged(Cie) = .empty,
eh_frame_data: std.ArrayListUnmanaged(u8) = .empty,
alive: bool = true,
dirty: bool = true,
num_dynrelocs: u32 = 0,
output_symtab_ctx: Elf.SymtabCtx = .{},
@ -917,7 +918,7 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
});
const atom_list = &elf_file.sections.items(.atom_list_2)[osec];
atom_list.output_section_index = osec;
try atom_list.atoms.append(elf_file.base.comp.gpa, atom_ptr.ref());
_ = try atom_list.atoms.getOrPut(elf_file.base.comp.gpa, atom_ptr.ref());
}
}

View File

@ -112,13 +112,16 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true, trampoline: bool
if (symbol.flags.has_trampoline and opts.trampoline) {
return symbol.trampolineAddress(elf_file);
}
if (symbol.flags.has_plt and opts.plt) {
if (!symbol.flags.is_canonical and symbol.flags.has_got) {
if (opts.plt) {
if (symbol.flags.has_pltgot) {
assert(!symbol.flags.is_canonical);
// We have a non-lazy bound function pointer, use that!
return symbol.pltGotAddress(elf_file);
}
// Lazy-bound function it is!
return symbol.pltAddress(elf_file);
if (symbol.flags.has_plt) {
// Lazy-bound function it is!
return symbol.pltAddress(elf_file);
}
}
if (symbol.atom(elf_file)) |atom_ptr| {
if (!atom_ptr.alive) {
@ -171,7 +174,7 @@ pub fn gotAddress(symbol: Symbol, elf_file: *Elf) i64 {
}
pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0;
if (!symbol.flags.has_pltgot) return 0;
const extras = symbol.extra(elf_file);
const shdr = elf_file.sections.items(.shdr)[elf_file.plt_got_section_index.?];
const cpu_arch = elf_file.getTarget().cpu.arch;
@ -430,6 +433,8 @@ pub const Flags = packed struct {
has_plt: bool = false,
/// Whether the PLT entry is canonical.
is_canonical: bool = false,
/// Whether the PLT entry is indirected via GOT.
has_pltgot: bool = false,
/// Whether the symbol contains COPYREL directive.
needs_copy_rel: bool = false,

View File

@ -101,6 +101,28 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.dwarf => |v| {
var dwarf = Dwarf.init(&elf_file.base, v);
const addSectionSymbolWithAtom = struct {
fn addSectionSymbolWithAtom(
zo: *ZigObject,
allocator: Allocator,
name: [:0]const u8,
alignment: Atom.Alignment,
shndx: u32,
) !Symbol.Index {
const name_off = try zo.addString(allocator, name);
const sym_index = try zo.addSectionSymbol(allocator, name_off, shndx);
const sym = zo.symbol(sym_index);
const atom_index = try zo.newAtom(allocator, name_off);
const atom_ptr = zo.atom(atom_index).?;
atom_ptr.alignment = alignment;
atom_ptr.output_section_index = shndx;
sym.ref = .{ .index = atom_index, .file = zo.index };
zo.symtab.items(.shndx)[sym.esym_index] = atom_index;
zo.symtab.items(.elf_sym)[sym.esym_index].st_shndx = SHN_ATOM;
return sym_index;
}
}.addSectionSymbolWithAtom;
if (self.debug_str_index == null) {
const osec = try elf_file.addSection(.{
.name = try elf_file.insertShString(".debug_str"),
@ -110,8 +132,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.addralign = 1,
});
self.debug_str_section_dirty = true;
self.debug_str_index = try self.addSectionSymbol(gpa, ".debug_str", .@"1", osec);
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_str_index.?).ref;
self.debug_str_index = try addSectionSymbolWithAtom(self, gpa, ".debug_str", .@"1", osec);
}
if (self.debug_info_index == null) {
@ -121,8 +142,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.addralign = 1,
});
self.debug_info_section_dirty = true;
self.debug_info_index = try self.addSectionSymbol(gpa, ".debug_info", .@"1", osec);
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_info_index.?).ref;
self.debug_info_index = try addSectionSymbolWithAtom(self, gpa, ".debug_info", .@"1", osec);
}
if (self.debug_abbrev_index == null) {
@ -132,8 +152,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.addralign = 1,
});
self.debug_abbrev_section_dirty = true;
self.debug_abbrev_index = try self.addSectionSymbol(gpa, ".debug_abbrev", .@"1", osec);
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_abbrev_index.?).ref;
self.debug_abbrev_index = try addSectionSymbolWithAtom(self, gpa, ".debug_abbrev", .@"1", osec);
}
if (self.debug_aranges_index == null) {
@ -143,8 +162,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.addralign = 16,
});
self.debug_aranges_section_dirty = true;
self.debug_aranges_index = try self.addSectionSymbol(gpa, ".debug_aranges", .@"16", osec);
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_aranges_index.?).ref;
self.debug_aranges_index = try addSectionSymbolWithAtom(self, gpa, ".debug_aranges", .@"16", osec);
}
if (self.debug_line_index == null) {
@ -154,8 +172,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.addralign = 1,
});
self.debug_line_section_dirty = true;
self.debug_line_index = try self.addSectionSymbol(gpa, ".debug_line", .@"1", osec);
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_line_index.?).ref;
self.debug_line_index = try addSectionSymbolWithAtom(self, gpa, ".debug_line", .@"1", osec);
}
if (self.debug_line_str_index == null) {
@ -167,8 +184,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.addralign = 1,
});
self.debug_line_str_section_dirty = true;
self.debug_line_str_index = try self.addSectionSymbol(gpa, ".debug_line_str", .@"1", osec);
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_line_str_index.?).ref;
self.debug_line_str_index = try addSectionSymbolWithAtom(self, gpa, ".debug_line_str", .@"1", osec);
}
if (self.debug_loclists_index == null) {
@ -178,8 +194,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.addralign = 1,
});
self.debug_loclists_section_dirty = true;
self.debug_loclists_index = try self.addSectionSymbol(gpa, ".debug_loclists", .@"1", osec);
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_loclists_index.?).ref;
self.debug_loclists_index = try addSectionSymbolWithAtom(self, gpa, ".debug_loclists", .@"1", osec);
}
if (self.debug_rnglists_index == null) {
@ -189,8 +204,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.addralign = 1,
});
self.debug_rnglists_section_dirty = true;
self.debug_rnglists_index = try self.addSectionSymbol(gpa, ".debug_rnglists", .@"1", osec);
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_rnglists_index.?).ref;
self.debug_rnglists_index = try addSectionSymbolWithAtom(self, gpa, ".debug_rnglists", .@"1", osec);
}
if (self.eh_frame_index == null) {
@ -204,8 +218,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.addralign = ptr_size,
});
self.eh_frame_section_dirty = true;
self.eh_frame_index = try self.addSectionSymbol(gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), osec);
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.eh_frame_index.?).ref;
self.eh_frame_index = try addSectionSymbolWithAtom(self, gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), osec);
}
try dwarf.initMetadata();
@ -336,8 +349,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
const atom_ptr = self.atom(sym.ref.index).?;
if (!atom_ptr.alive) continue;
log.debug("parsing relocs in {s}", .{sym.name(elf_file)});
const relocs = &self.relocs.items[atom_ptr.relocsShndx().?];
for (sect.units.items) |*unit| {
try relocs.ensureUnusedCapacity(gpa, unit.cross_unit_relocs.items.len +
@ -350,12 +361,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
else
0));
const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
self.symbol(sym_index).name(elf_file),
r_offset,
r_addend,
relocation.fmtRelocType(r_type, cpu_arch),
});
atom_ptr.addRelocAssumeCapacity(.{
.r_offset = r_offset,
.r_addend = r_addend,
@ -384,12 +389,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
else
0));
const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
self.symbol(target_sym_index).name(elf_file),
r_offset,
r_addend,
relocation.fmtRelocType(r_type, cpu_arch),
});
atom_ptr.addRelocAssumeCapacity(.{
.r_offset = r_offset,
.r_addend = r_addend,
@ -410,12 +409,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
else
0));
const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
self.symbol(sym_index).name(elf_file),
r_offset,
r_addend,
relocation.fmtRelocType(r_type, cpu_arch),
});
atom_ptr.addRelocAssumeCapacity(.{
.r_offset = r_offset,
.r_addend = r_addend,
@ -430,12 +423,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
else
0));
const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
self.symbol(sym_index).name(elf_file),
r_offset,
r_addend,
relocation.fmtRelocType(r_type, cpu_arch),
});
atom_ptr.addRelocAssumeCapacity(.{
.r_offset = r_offset,
.r_addend = r_addend,
@ -464,12 +451,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
else
0));
const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
self.symbol(target_sym_index).name(elf_file),
r_offset,
r_addend,
relocation.fmtRelocType(r_type, cpu_arch),
});
atom_ptr.addRelocAssumeCapacity(.{
.r_offset = r_offset,
.r_addend = r_addend,
@ -481,12 +462,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
const r_offset = entry_off + reloc.source_off;
const r_addend: i64 = @intCast(reloc.target_off);
const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch);
log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
target_sym.name(elf_file),
r_offset,
r_addend,
relocation.fmtRelocType(r_type, cpu_arch),
});
atom_ptr.addRelocAssumeCapacity(.{
.r_offset = r_offset,
.r_addend = r_addend,
@ -1035,16 +1010,15 @@ pub fn lowerUav(
}
const osec = if (self.data_relro_index) |sym_index|
self.symbol(sym_index).atom(elf_file).?.output_section_index
self.symbol(sym_index).outputShndx(elf_file).?
else osec: {
const osec = try elf_file.addSection(.{
.name = try elf_file.insertShString(".data.rel.ro"),
.type = elf.SHT_PROGBITS,
.addralign = 1,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
.offset = std.math.maxInt(u64),
});
self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec);
self.data_relro_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data.rel.ro"), osec);
break :osec osec;
};
@ -1150,24 +1124,14 @@ pub fn getOrCreateMetadataForNav(
return gop.value_ptr.symbol_index;
}
// FIXME: we always create an atom to basically store size and alignment, however, this is only true for
// sections that have a single atom like the debug sections. It would be a better solution to decouple this
// concept from the atom, maybe.
fn addSectionSymbol(
self: *ZigObject,
allocator: Allocator,
name: [:0]const u8,
alignment: Atom.Alignment,
shndx: u32,
) !Symbol.Index {
const name_off = try self.addString(allocator, name);
const index = try self.newSymbolWithAtom(allocator, name_off);
fn addSectionSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, shndx: u32) !Symbol.Index {
const index = try self.newLocalSymbol(allocator, name_off);
const sym = self.symbol(index);
const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
esym.st_info |= elf.STT_SECTION;
const atom_ptr = self.atom(sym.ref.index).?;
atom_ptr.alignment = alignment;
atom_ptr.output_section_index = shndx;
// TODO create fake shdrs?
// esym.st_shndx = shndx;
sym.output_section_index = shndx;
return index;
}
@ -1186,15 +1150,14 @@ fn getNavShdrIndex(
const nav_val = zcu.navValue(nav_index);
if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) {
if (self.text_index) |symbol_index|
return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
return self.symbol(symbol_index).outputShndx(elf_file).?;
const osec = try elf_file.addSection(.{
.type = elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
.name = try elf_file.insertShString(".text"),
.addralign = 1,
.offset = std.math.maxInt(u64),
});
self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec);
self.text_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".text"), osec);
return osec;
}
const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
@ -1209,71 +1172,63 @@ fn getNavShdrIndex(
} else true;
if (is_bss) {
if (self.tbss_index) |symbol_index|
return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
return self.symbol(symbol_index).outputShndx(elf_file).?;
const osec = try elf_file.addSection(.{
.name = try elf_file.insertShString(".tbss"),
.flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
.type = elf.SHT_NOBITS,
.addralign = 1,
});
self.tbss_index = try self.addSectionSymbol(gpa, ".tbss", .@"1", osec);
self.tbss_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".tbss"), osec);
return osec;
}
if (self.tdata_index) |symbol_index|
return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
return self.symbol(symbol_index).outputShndx(elf_file).?;
const osec = try elf_file.addSection(.{
.type = elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
.name = try elf_file.insertShString(".tdata"),
.addralign = 1,
.offset = std.math.maxInt(u64),
});
self.tdata_index = try self.addSectionSymbol(gpa, ".tdata", .@"1", osec);
self.tdata_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".tdata"), osec);
return osec;
}
if (is_const) {
if (self.data_relro_index) |symbol_index|
return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
return self.symbol(symbol_index).outputShndx(elf_file).?;
const osec = try elf_file.addSection(.{
.name = try elf_file.insertShString(".data.rel.ro"),
.type = elf.SHT_PROGBITS,
.addralign = 1,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
.offset = std.math.maxInt(u64),
});
self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec);
self.data_relro_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data.rel.ro"), osec);
return osec;
}
if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu))
return switch (zcu.navFileScope(nav_index).mod.optimize_mode) {
.Debug, .ReleaseSafe => {
if (self.data_index) |symbol_index|
return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
return self.symbol(symbol_index).outputShndx(elf_file).?;
const osec = try elf_file.addSection(.{
.name = try elf_file.insertShString(".data"),
.type = elf.SHT_PROGBITS,
.addralign = ptr_size,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
.offset = std.math.maxInt(u64),
});
self.data_index = try self.addSectionSymbol(
gpa,
".data",
Atom.Alignment.fromNonzeroByteUnits(ptr_size),
osec,
);
self.data_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data"), osec);
return osec;
},
.ReleaseFast, .ReleaseSmall => {
if (self.bss_index) |symbol_index|
return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
return self.symbol(symbol_index).outputShndx(elf_file).?;
const osec = try elf_file.addSection(.{
.type = elf.SHT_NOBITS,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
.name = try elf_file.insertShString(".bss"),
.addralign = 1,
});
self.bss_index = try self.addSectionSymbol(gpa, ".bss", .@"1", osec);
self.bss_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".bss"), osec);
return osec;
},
};
@ -1282,31 +1237,25 @@ fn getNavShdrIndex(
} else true;
if (is_bss) {
if (self.bss_index) |symbol_index|
return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
return self.symbol(symbol_index).outputShndx(elf_file).?;
const osec = try elf_file.addSection(.{
.type = elf.SHT_NOBITS,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
.name = try elf_file.insertShString(".bss"),
.addralign = 1,
});
self.bss_index = try self.addSectionSymbol(gpa, ".bss", .@"1", osec);
self.bss_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".bss"), osec);
return osec;
}
if (self.data_index) |symbol_index|
return self.symbol(symbol_index).atom(elf_file).?.output_section_index;
return self.symbol(symbol_index).outputShndx(elf_file).?;
const osec = try elf_file.addSection(.{
.name = try elf_file.insertShString(".data"),
.type = elf.SHT_PROGBITS,
.addralign = ptr_size,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
.offset = std.math.maxInt(u64),
});
self.data_index = try self.addSectionSymbol(
gpa,
".data",
Atom.Alignment.fromNonzeroByteUnits(ptr_size),
osec,
);
self.data_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data"), osec);
return osec;
}
@ -1354,7 +1303,7 @@ fn updateNavCode(
const capacity = atom_ptr.capacity(elf_file);
const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value));
if (need_realloc) {
try self.growAtom(atom_ptr, elf_file);
try self.allocateAtom(atom_ptr, true, elf_file);
log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value });
if (old_vaddr != atom_ptr.value) {
sym.value = 0;
@ -1364,7 +1313,7 @@ fn updateNavCode(
// TODO shrink section size
}
} else {
try self.allocateAtom(atom_ptr, elf_file);
try self.allocateAtom(atom_ptr, true, elf_file);
errdefer self.freeNavMetadata(elf_file, sym_index);
sym.value = 0;
esym.st_value = 0;
@ -1439,7 +1388,7 @@ fn updateTlv(
const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index);
assert(!gop.found_existing); // TODO incremental updates
try self.allocateAtom(atom_ptr, elf_file);
try self.allocateAtom(atom_ptr, true, elf_file);
sym.value = 0;
esym.st_value = 0;
@ -1557,9 +1506,8 @@ pub fn updateFunc(
.flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
.type = elf.SHT_PROGBITS,
.addralign = 1,
.offset = std.math.maxInt(u64),
});
self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec);
self.text_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".text"), osec);
break :osec osec;
};
const name_off = try self.addString(gpa, name);
@ -1726,29 +1674,27 @@ fn updateLazySymbol(
const output_section_index = switch (sym.kind) {
.code => if (self.text_index) |sym_index|
self.symbol(sym_index).atom(elf_file).?.output_section_index
self.symbol(sym_index).outputShndx(elf_file).?
else osec: {
const osec = try elf_file.addSection(.{
.name = try elf_file.insertShString(".text"),
.type = elf.SHT_PROGBITS,
.addralign = 1,
.flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
.offset = std.math.maxInt(u64),
});
self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec);
self.text_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".text"), osec);
break :osec osec;
},
.const_data => if (self.rodata_index) |sym_index|
self.symbol(sym_index).atom(elf_file).?.output_section_index
self.symbol(sym_index).outputShndx(elf_file).?
else osec: {
const osec = try elf_file.addSection(.{
.name = try elf_file.insertShString(".rodata"),
.type = elf.SHT_PROGBITS,
.addralign = 1,
.flags = elf.SHF_ALLOC,
.offset = std.math.maxInt(u64),
});
self.rodata_index = try self.addSectionSymbol(gpa, ".rodata", .@"1", osec);
self.rodata_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".rodata"), osec);
break :osec osec;
},
};
@ -1765,7 +1711,7 @@ fn updateLazySymbol(
atom_ptr.size = code.len;
atom_ptr.output_section_index = output_section_index;
try self.allocateAtom(atom_ptr, elf_file);
try self.allocateAtom(atom_ptr, true, elf_file);
errdefer self.freeNavMetadata(elf_file, symbol_index);
local_sym.value = 0;
@ -1820,7 +1766,7 @@ fn lowerConst(
atom_ptr.size = code.len;
atom_ptr.output_section_index = output_section_index;
try self.allocateAtom(atom_ptr, elf_file);
try self.allocateAtom(atom_ptr, true, elf_file);
errdefer self.freeNavMetadata(elf_file, sym_index);
try elf_file.base.file.?.pwriteAll(code, atom_ptr.offset(elf_file));
@ -2017,17 +1963,27 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
}
}
fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
pub fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, requires_padding: bool, elf_file: *Elf) !void {
const slice = elf_file.sections.slice();
const shdr = &slice.items(.shdr)[atom_ptr.output_section_index];
const last_atom_ref = &slice.items(.last_atom)[atom_ptr.output_section_index];
// FIXME:JK this only works if this atom is the only atom in the output section
// In every other case, we need to redo the prev/next links
if (last_atom_ref.eql(atom_ptr.ref())) last_atom_ref.* = .{};
const alloc_res = try elf_file.allocateChunk(.{
.shndx = atom_ptr.output_section_index,
.size = atom_ptr.size,
.alignment = atom_ptr.alignment,
.requires_padding = requires_padding,
});
atom_ptr.value = @intCast(alloc_res.value);
const slice = elf_file.sections.slice();
const shdr = &slice.items(.shdr)[atom_ptr.output_section_index];
const last_atom_ref = &slice.items(.last_atom)[atom_ptr.output_section_index];
log.debug("allocated {s} at {x}\n placement {?}", .{
atom_ptr.name(elf_file),
atom_ptr.offset(elf_file),
alloc_res.placement,
});
const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom|
placement_atom.nextAtom(elf_file) == null
@ -2049,22 +2005,6 @@ fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
}
shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits().?);
const sect_atom_ptr = for ([_]?Symbol.Index{
self.text_index,
self.rodata_index,
self.data_relro_index,
self.data_index,
self.tdata_index,
}) |maybe_sym_index| {
const sect_sym_index = maybe_sym_index orelse continue;
const sect_atom_ptr = self.symbol(sect_sym_index).atom(elf_file).?;
if (sect_atom_ptr.output_section_index == atom_ptr.output_section_index) break sect_atom_ptr;
} else null;
if (sect_atom_ptr) |sap| {
sap.size = shdr.sh_size;
sap.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
}
// 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.
@ -2083,11 +2023,37 @@ fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
atom_ptr.prev_atom_ref = .{ .index = 0, .file = 0 };
atom_ptr.next_atom_ref = .{ .index = 0, .file = 0 };
}
log.debug(" prev {?}, next {?}", .{ atom_ptr.prev_atom_ref, atom_ptr.next_atom_ref });
}
fn growAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
if (!atom_ptr.alignment.check(@intCast(atom_ptr.value)) or atom_ptr.size > atom_ptr.capacity(elf_file)) {
try self.allocateAtom(atom_ptr, elf_file);
pub fn resetShdrIndexes(self: *ZigObject, backlinks: anytype) void {
for (self.atoms_indexes.items) |atom_index| {
const atom_ptr = self.atom(atom_index) orelse continue;
atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
}
inline for ([_]?Symbol.Index{
self.text_index,
self.rodata_index,
self.data_relro_index,
self.data_index,
self.bss_index,
self.tdata_index,
self.tbss_index,
self.eh_frame_index,
self.debug_info_index,
self.debug_abbrev_index,
self.debug_aranges_index,
self.debug_str_index,
self.debug_line_index,
self.debug_line_str_index,
self.debug_loclists_index,
self.debug_rnglists_index,
}) |maybe_sym_index| {
if (maybe_sym_index) |sym_index| {
const sym = self.symbol(sym_index);
sym.output_section_index = backlinks[sym.output_section_index];
}
}
}
@ -2095,6 +2061,33 @@ pub fn asFile(self: *ZigObject) File {
return .{ .zig_object = self };
}
pub fn sectionSymbol(self: *ZigObject, shndx: u32, elf_file: *Elf) ?*Symbol {
inline for ([_]?Symbol.Index{
self.text_index,
self.rodata_index,
self.data_relro_index,
self.data_index,
self.bss_index,
self.tdata_index,
self.tbss_index,
self.eh_frame_index,
self.debug_info_index,
self.debug_abbrev_index,
self.debug_aranges_index,
self.debug_str_index,
self.debug_line_index,
self.debug_line_str_index,
self.debug_loclists_index,
self.debug_rnglists_index,
}) |maybe_sym_index| {
if (maybe_sym_index) |sym_index| {
const sym = self.symbol(sym_index);
if (sym.outputShndx(elf_file) == shndx) return sym;
}
}
return null;
}
pub fn addString(self: *ZigObject, allocator: Allocator, string: []const u8) !u32 {
return self.strtab.insert(allocator, string);
}

View File

@ -95,19 +95,19 @@ pub const File = union(enum) {
log.debug("'{s}' is non-local", .{sym.name(ef)});
try ef.dynsym.addSymbol(ref, ef);
}
if (sym.flags.needs_got) {
if (sym.flags.needs_got and !sym.flags.has_got) {
log.debug("'{s}' needs GOT", .{sym.name(ef)});
_ = try ef.got.addGotSymbol(ref, ef);
}
if (sym.flags.needs_plt) {
if (sym.flags.is_canonical) {
if (sym.flags.is_canonical and !sym.flags.has_plt) {
log.debug("'{s}' needs CPLT", .{sym.name(ef)});
sym.flags.@"export" = true;
try ef.plt.addSymbol(ref, ef);
} else if (sym.flags.needs_got) {
} else if (sym.flags.needs_got and !sym.flags.has_pltgot) {
log.debug("'{s}' needs PLTGOT", .{sym.name(ef)});
try ef.plt_got.addSymbol(ref, ef);
} else {
} else if (!sym.flags.has_plt) {
log.debug("'{s}' needs PLT", .{sym.name(ef)});
try ef.plt.addSymbol(ref, ef);
}
@ -116,15 +116,15 @@ pub const File = union(enum) {
log.debug("'{s}' needs COPYREL", .{sym.name(ef)});
try ef.copy_rel.addSymbol(ref, ef);
}
if (sym.flags.needs_tlsgd) {
if (sym.flags.needs_tlsgd and !sym.flags.has_tlsgd) {
log.debug("'{s}' needs TLSGD", .{sym.name(ef)});
try ef.got.addTlsGdSymbol(ref, ef);
}
if (sym.flags.needs_gottp) {
if (sym.flags.needs_gottp and !sym.flags.has_gottp) {
log.debug("'{s}' needs GOTTP", .{sym.name(ef)});
try ef.got.addGotTpSymbol(ref, ef);
}
if (sym.flags.needs_tlsdesc) {
if (sym.flags.needs_tlsdesc and !sym.flags.has_tlsdesc) {
log.debug("'{s}' needs TLSDESC", .{sym.name(ef)});
try ef.got.addTlsDescSymbol(ref, ef);
}

View File

@ -295,7 +295,6 @@ fn initSections(elf_file: *Elf) !void {
elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC,
.addralign = elf_file.ptrWidthBytes(),
.offset = std.math.maxInt(u64),
});
}
elf_file.eh_frame_rela_section_index = elf_file.sectionByName(".rela.eh_frame") orelse
@ -324,7 +323,6 @@ fn initComdatGroups(elf_file: *Elf) !void {
.type = elf.SHT_GROUP,
.entsize = @sizeOf(u32),
.addralign = @alignOf(u32),
.offset = std.math.maxInt(u64),
}),
.cg_ref = .{ .index = @intCast(cg_index), .file = index },
};
@ -335,9 +333,11 @@ fn initComdatGroups(elf_file: *Elf) !void {
fn updateSectionSizes(elf_file: *Elf) !void {
const slice = elf_file.sections.slice();
for (slice.items(.atom_list_2)) |*atom_list| {
if (atom_list.atoms.items.len == 0) continue;
if (atom_list.atoms.keys().len == 0) continue;
if (!atom_list.dirty) continue;
atom_list.updateSize(elf_file);
try atom_list.allocate(elf_file);
atom_list.dirty = false;
}
for (slice.items(.shdr), 0..) |*shdr, shndx| {
@ -392,24 +392,14 @@ fn allocateAllocSections(elf_file: *Elf) !void {
shdr.sh_size = 0;
const new_offset = try elf_file.findFreeSpace(needed_size, shdr.sh_addralign);
if (elf_file.zigObjectPtr()) |zo| blk: {
const existing_size = for ([_]?Symbol.Index{
zo.text_index,
zo.rodata_index,
zo.data_relro_index,
zo.data_index,
zo.tdata_index,
zo.eh_frame_index,
}) |maybe_sym_index| {
const sect_sym_index = maybe_sym_index orelse continue;
const sect_atom_ptr = zo.symbol(sect_sym_index).atom(elf_file).?;
if (sect_atom_ptr.output_section_index == shndx) break sect_atom_ptr.size;
} else break :blk;
log.debug("moving {s} from 0x{x} to 0x{x}", .{
elf_file.getShString(shdr.sh_name),
shdr.sh_offset,
new_offset,
});
log.debug("moving {s} from 0x{x} to 0x{x}", .{
elf_file.getShString(shdr.sh_name),
shdr.sh_offset,
new_offset,
});
if (shdr.sh_offset > 0) {
const existing_size = elf_file.sectionSize(@intCast(shndx));
const amt = try elf_file.base.file.?.copyRangeAll(
shdr.sh_offset,
elf_file.base.file.?,
@ -434,7 +424,7 @@ fn writeAtoms(elf_file: *Elf) !void {
const slice = elf_file.sections.slice();
for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| {
if (shdr.sh_type == elf.SHT_NOBITS) continue;
if (atom_list.atoms.items.len == 0) continue;
if (atom_list.atoms.keys().len == 0) continue;
try atom_list.writeRelocatable(&buffer, elf_file);
}
}

View File

@ -435,6 +435,8 @@ pub const GotSection = struct {
const cpu_arch = elf_file.getTarget().cpu.arch;
try elf_file.rela_dyn.ensureUnusedCapacity(gpa, got.numRela(elf_file));
relocs_log.debug(".got", .{});
for (got.entries.items) |entry| {
const symbol = elf_file.symbol(entry.ref);
const extra = if (symbol) |s| s.extra(elf_file) else null;
@ -447,6 +449,7 @@ pub const GotSection = struct {
.offset = offset,
.sym = extra.?.dynamic,
.type = relocation.encode(.glob_dat, cpu_arch),
.target = symbol,
});
continue;
}
@ -455,6 +458,7 @@ pub const GotSection = struct {
.offset = offset,
.type = relocation.encode(.irel, cpu_arch),
.addend = symbol.?.address(.{ .plt = false }, elf_file),
.target = symbol,
});
continue;
}
@ -465,6 +469,7 @@ pub const GotSection = struct {
.offset = offset,
.type = relocation.encode(.rel, cpu_arch),
.addend = symbol.?.address(.{ .plt = false }, elf_file),
.target = symbol,
});
}
},
@ -486,17 +491,20 @@ pub const GotSection = struct {
.offset = offset,
.sym = extra.?.dynamic,
.type = relocation.encode(.dtpmod, cpu_arch),
.target = symbol,
});
elf_file.addRelaDynAssumeCapacity(.{
.offset = offset + 8,
.sym = extra.?.dynamic,
.type = relocation.encode(.dtpoff, cpu_arch),
.target = symbol,
});
} else if (is_dyn_lib) {
elf_file.addRelaDynAssumeCapacity(.{
.offset = offset,
.sym = extra.?.dynamic,
.type = relocation.encode(.dtpmod, cpu_arch),
.target = symbol,
});
}
},
@ -508,12 +516,14 @@ pub const GotSection = struct {
.offset = offset,
.sym = extra.?.dynamic,
.type = relocation.encode(.tpoff, cpu_arch),
.target = symbol,
});
} else if (is_dyn_lib) {
elf_file.addRelaDynAssumeCapacity(.{
.offset = offset,
.type = relocation.encode(.tpoff, cpu_arch),
.addend = symbol.?.address(.{}, elf_file) - elf_file.tlsAddress(),
.target = symbol,
});
}
},
@ -525,6 +535,7 @@ pub const GotSection = struct {
.sym = if (symbol.?.flags.import) extra.?.dynamic else 0,
.type = relocation.encode(.tlsdesc, cpu_arch),
.addend = if (symbol.?.flags.import) 0 else symbol.?.address(.{}, elf_file) - elf_file.tlsAddress(),
.target = symbol,
});
},
}
@ -681,6 +692,9 @@ pub const PltSection = struct {
const gpa = comp.gpa;
const cpu_arch = elf_file.getTarget().cpu.arch;
try elf_file.rela_plt.ensureUnusedCapacity(gpa, plt.numRela());
relocs_log.debug(".plt", .{});
for (plt.symbols.items) |ref| {
const sym = elf_file.symbol(ref).?;
assert(sym.flags.import);
@ -688,6 +702,14 @@ pub const PltSection = struct {
const r_offset: u64 = @intCast(sym.gotPltAddress(elf_file));
const r_sym: u64 = extra.dynamic;
const r_type = relocation.encode(.jump_slot, cpu_arch);
relocs_log.debug(" {s}: [{x} => {d}({s})] + 0", .{
relocation.fmtRelocType(r_type, cpu_arch),
r_offset,
r_sym,
sym.name(elf_file),
});
elf_file.rela_plt.appendAssumeCapacity(.{
.r_offset = r_offset,
.r_info = (r_sym << 32) | r_type,
@ -895,8 +917,7 @@ pub const PltGotSection = struct {
const gpa = comp.gpa;
const index = @as(u32, @intCast(plt_got.symbols.items.len));
const symbol = elf_file.symbol(ref).?;
symbol.flags.has_plt = true;
symbol.flags.has_got = true;
symbol.flags.has_pltgot = true;
symbol.addExtra(.{ .plt_got = index }, elf_file);
try plt_got.symbols.append(gpa, ref);
}
@ -1054,6 +1075,9 @@ pub const CopyRelSection = struct {
const gpa = comp.gpa;
const cpu_arch = elf_file.getTarget().cpu.arch;
try elf_file.rela_dyn.ensureUnusedCapacity(gpa, copy_rel.numRela());
relocs_log.debug(".copy.rel", .{});
for (copy_rel.symbols.items) |ref| {
const sym = elf_file.symbol(ref).?;
assert(sym.flags.import and sym.flags.has_copy_rel);
@ -1526,6 +1550,7 @@ const elf = std.elf;
const math = std.math;
const mem = std.mem;
const log = std.log.scoped(.link);
const relocs_log = std.log.scoped(.link_relocs);
const relocation = @import("relocation.zig");
const std = @import("std");