mirror of
https://github.com/ziglang/zig.git
synced 2024-11-26 15:12:31 +00:00
elf: change how we manage debug atoms in Dwarf linker
This commit is contained in:
parent
a3b2c0488f
commit
db769a8764
@ -389,14 +389,20 @@ 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 needed_size = len;
|
||||
const min_alignment = sec.alignment.toByteUnits().?;
|
||||
try elf_file.growSection(shndx, needed_size, min_alignment);
|
||||
const shdr = elf_file.sections.items(.shdr)[shndx];
|
||||
atom.size = needed_size;
|
||||
atom.alignment = InternPool.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
|
||||
sec.len = needed_size;
|
||||
const old_size = atom.size;
|
||||
atom.size = len;
|
||||
atom.alignment = sec.alignment;
|
||||
sec.len = len;
|
||||
if (old_size > 0) {
|
||||
if (!atom.alignment.check(@intCast(atom.value)) or atom.size > atom.fileCapacity(elf_file)) {
|
||||
try zo.allocateAtom(atom, false, elf_file);
|
||||
} else {
|
||||
const shdr = &elf_file.sections.items(.shdr)[atom.output_section_index];
|
||||
shdr.sh_size = (shdr.sh_size - old_size) + atom.size;
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
@ -417,11 +423,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]
|
||||
@ -910,11 +920,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
|
||||
|
@ -561,10 +561,10 @@ pub fn growSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment:
|
||||
// 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(
|
||||
@ -679,13 +679,6 @@ 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
|
||||
@ -695,6 +688,18 @@ pub fn allocateChunk(self: *Elf, args: struct {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1969,6 +1974,7 @@ pub fn initOutputSection(self: *Elf, args: struct {
|
||||
.type = @"type",
|
||||
.flags = flags,
|
||||
.name = try self.insertShString(name),
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
return out_shndx;
|
||||
}
|
||||
@ -4065,27 +4071,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.?,
|
||||
|
@ -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;
|
||||
|
@ -130,10 +130,10 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
|
||||
.entsize = 1,
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.addralign = 1,
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
self.debug_str_section_dirty = true;
|
||||
self.debug_str_index = try addSectionSymbolWithAtom(self, gpa, ".debug_str", .@"1", osec);
|
||||
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_str_index.?).ref;
|
||||
}
|
||||
|
||||
if (self.debug_info_index == null) {
|
||||
@ -141,10 +141,10 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
|
||||
.name = try elf_file.insertShString(".debug_info"),
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.addralign = 1,
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
self.debug_info_section_dirty = true;
|
||||
self.debug_info_index = try addSectionSymbolWithAtom(self, gpa, ".debug_info", .@"1", osec);
|
||||
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_info_index.?).ref;
|
||||
}
|
||||
|
||||
if (self.debug_abbrev_index == null) {
|
||||
@ -152,10 +152,10 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
|
||||
.name = try elf_file.insertShString(".debug_abbrev"),
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.addralign = 1,
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
self.debug_abbrev_section_dirty = true;
|
||||
self.debug_abbrev_index = try addSectionSymbolWithAtom(self, gpa, ".debug_abbrev", .@"1", osec);
|
||||
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_abbrev_index.?).ref;
|
||||
}
|
||||
|
||||
if (self.debug_aranges_index == null) {
|
||||
@ -163,10 +163,10 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
|
||||
.name = try elf_file.insertShString(".debug_aranges"),
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.addralign = 16,
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
self.debug_aranges_section_dirty = true;
|
||||
self.debug_aranges_index = try addSectionSymbolWithAtom(self, gpa, ".debug_aranges", .@"16", osec);
|
||||
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_aranges_index.?).ref;
|
||||
}
|
||||
|
||||
if (self.debug_line_index == null) {
|
||||
@ -174,10 +174,10 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
|
||||
.name = try elf_file.insertShString(".debug_line"),
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.addralign = 1,
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
self.debug_line_section_dirty = true;
|
||||
self.debug_line_index = try addSectionSymbolWithAtom(self, gpa, ".debug_line", .@"1", osec);
|
||||
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_line_index.?).ref;
|
||||
}
|
||||
|
||||
if (self.debug_line_str_index == null) {
|
||||
@ -187,10 +187,10 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
|
||||
.entsize = 1,
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.addralign = 1,
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
self.debug_line_str_section_dirty = true;
|
||||
self.debug_line_str_index = try addSectionSymbolWithAtom(self, gpa, ".debug_line_str", .@"1", osec);
|
||||
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_line_str_index.?).ref;
|
||||
}
|
||||
|
||||
if (self.debug_loclists_index == null) {
|
||||
@ -198,10 +198,10 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
|
||||
.name = try elf_file.insertShString(".debug_loclists"),
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.addralign = 1,
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
self.debug_loclists_section_dirty = true;
|
||||
self.debug_loclists_index = try addSectionSymbolWithAtom(self, gpa, ".debug_loclists", .@"1", osec);
|
||||
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_loclists_index.?).ref;
|
||||
}
|
||||
|
||||
if (self.debug_rnglists_index == null) {
|
||||
@ -209,10 +209,10 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
|
||||
.name = try elf_file.insertShString(".debug_rnglists"),
|
||||
.type = elf.SHT_PROGBITS,
|
||||
.addralign = 1,
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
self.debug_rnglists_section_dirty = true;
|
||||
self.debug_rnglists_index = try addSectionSymbolWithAtom(self, gpa, ".debug_rnglists", .@"1", osec);
|
||||
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_rnglists_index.?).ref;
|
||||
}
|
||||
|
||||
if (self.eh_frame_index == null) {
|
||||
@ -224,10 +224,10 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
|
||||
elf.SHT_PROGBITS,
|
||||
.flags = elf.SHF_ALLOC,
|
||||
.addralign = ptr_size,
|
||||
.offset = std.math.maxInt(u64),
|
||||
});
|
||||
self.eh_frame_section_dirty = true;
|
||||
self.eh_frame_index = try addSectionSymbolWithAtom(self, gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), osec);
|
||||
elf_file.sections.items(.last_atom)[osec] = self.symbol(self.eh_frame_index.?).ref;
|
||||
}
|
||||
|
||||
try dwarf.initMetadata();
|
||||
@ -1318,7 +1318,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;
|
||||
@ -1328,7 +1328,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;
|
||||
@ -1403,7 +1403,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;
|
||||
|
||||
@ -1729,7 +1729,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;
|
||||
@ -1784,7 +1784,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));
|
||||
@ -1981,17 +1981,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
|
||||
@ -2013,12 +2023,6 @@ fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void {
|
||||
}
|
||||
shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits().?);
|
||||
|
||||
if (self.sectionSymbol(atom_ptr.output_section_index, elf_file)) |sym| {
|
||||
assert(sym.atom(elf_file) == null and sym.mergeSubsection(elf_file) == null);
|
||||
const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
|
||||
esym.st_size += atom_ptr.size + Elf.padToIdeal(atom_ptr.size);
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -2037,12 +2041,8 @@ 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 };
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
log.debug(" prev {?}, next {?}", .{ atom_ptr.prev_atom_ref, atom_ptr.next_atom_ref });
|
||||
}
|
||||
|
||||
pub fn resetShdrIndexes(self: *ZigObject, backlinks: anytype) void {
|
||||
|
@ -414,24 +414,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.?,
|
||||
|
Loading…
Reference in New Issue
Block a user