mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 02:44:43 +01:00
elf: allow for concatenating atoms to merge sections
This commit is contained in:
parent
b2fad5c58b
commit
6c731be3a1
5 changed files with 105 additions and 68 deletions
|
|
@ -1282,7 +1282,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
|
|||
try self.addCommentString();
|
||||
try self.finalizeMergeSections();
|
||||
try self.initOutputSections();
|
||||
try self.initMergeSections();
|
||||
if (self.linkerDefinedPtr()) |obj| {
|
||||
try obj.initStartStopSymbols(self);
|
||||
}
|
||||
|
|
@ -3048,17 +3047,17 @@ pub fn finalizeMergeSections(self: *Elf) !void {
|
|||
}
|
||||
|
||||
pub fn updateMergeSectionSizes(self: *Elf) !void {
|
||||
for (self.merge_sections.items) |*msec| {
|
||||
msec.updateSize();
|
||||
}
|
||||
for (self.merge_sections.items) |*msec| {
|
||||
const shdr = &self.shdrs.items[msec.output_section_index];
|
||||
for (msec.finalized_subsections.items) |msub_index| {
|
||||
const msub = msec.mergeSubsection(msub_index);
|
||||
assert(msub.alive);
|
||||
const offset = msub.alignment.forward(shdr.sh_size);
|
||||
const padding = offset - shdr.sh_size;
|
||||
msub.value = @intCast(offset);
|
||||
shdr.sh_size += padding + msub.size;
|
||||
shdr.sh_addralign = @max(shdr.sh_addralign, msub.alignment.toByteUnits() orelse 1);
|
||||
}
|
||||
const offset = msec.alignment.forward(shdr.sh_size);
|
||||
const padding = offset - shdr.sh_size;
|
||||
msec.value = @intCast(offset);
|
||||
shdr.sh_size += padding + msec.size;
|
||||
shdr.sh_addralign = @max(shdr.sh_addralign, msec.alignment.toByteUnits() orelse 1);
|
||||
shdr.sh_entsize = if (shdr.sh_entsize == 0) msec.entsize else @min(shdr.sh_entsize, msec.entsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3069,7 +3068,8 @@ pub fn writeMergeSections(self: *Elf) !void {
|
|||
|
||||
for (self.merge_sections.items) |*msec| {
|
||||
const shdr = self.shdrs.items[msec.output_section_index];
|
||||
const size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
|
||||
const fileoff = math.cast(usize, msec.value + shdr.sh_offset) orelse return error.Overflow;
|
||||
const size = math.cast(usize, msec.size) orelse return error.Overflow;
|
||||
try buffer.ensureTotalCapacity(size);
|
||||
buffer.appendNTimesAssumeCapacity(0, size);
|
||||
|
||||
|
|
@ -3081,7 +3081,7 @@ pub fn writeMergeSections(self: *Elf) !void {
|
|||
@memcpy(buffer.items[off..][0..string.len], string);
|
||||
}
|
||||
|
||||
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
|
||||
try self.base.file.?.pwriteAll(buffer.items, fileoff);
|
||||
buffer.clearRetainingCapacity();
|
||||
}
|
||||
}
|
||||
|
|
@ -3090,26 +3090,9 @@ fn initOutputSections(self: *Elf) !void {
|
|||
for (self.objects.items) |index| {
|
||||
try self.file(index).?.object.initOutputSections(self);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initMergeSections(self: *Elf) !void {
|
||||
for (self.merge_sections.items) |*msec| {
|
||||
if (msec.finalized_subsections.items.len == 0) continue;
|
||||
const name = msec.name(self);
|
||||
const shndx = self.sectionByName(name) orelse try self.addSection(.{
|
||||
.name = msec.name_offset,
|
||||
.type = msec.type,
|
||||
.flags = msec.flags,
|
||||
});
|
||||
msec.output_section_index = shndx;
|
||||
|
||||
var entsize = msec.mergeSubsection(msec.finalized_subsections.items[0]).entsize;
|
||||
for (msec.finalized_subsections.items) |msub_index| {
|
||||
const msub = msec.mergeSubsection(msub_index);
|
||||
entsize = @min(entsize, msub.entsize);
|
||||
}
|
||||
const shdr = &self.shdrs.items[shndx];
|
||||
shdr.sh_entsize = entsize;
|
||||
try msec.initOutputSection(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4427,7 +4410,6 @@ pub fn updateSymtabSize(self: *Elf) !void {
|
|||
if (self.eh_frame_section_index) |_| {
|
||||
nlocals += 1;
|
||||
}
|
||||
nlocals += @intCast(self.merge_sections.items.len);
|
||||
|
||||
if (self.requiresThunks()) for (self.thunks.items) |*th| {
|
||||
th.output_symtab_ctx.ilocal = nlocals + 1;
|
||||
|
|
@ -4751,30 +4733,12 @@ fn writeSectionSymbols(self: *Elf) void {
|
|||
};
|
||||
ilocal += 1;
|
||||
}
|
||||
|
||||
for (self.merge_sections.items) |msec| {
|
||||
const shdr = self.shdrs.items[msec.output_section_index];
|
||||
const out_sym = &self.symtab.items[ilocal];
|
||||
out_sym.* = .{
|
||||
.st_name = 0,
|
||||
.st_value = shdr.sh_addr,
|
||||
.st_info = elf.STT_SECTION,
|
||||
.st_shndx = @intCast(msec.output_section_index),
|
||||
.st_size = 0,
|
||||
.st_other = 0,
|
||||
};
|
||||
ilocal += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 {
|
||||
if (self.eh_frame_section_index) |index| {
|
||||
if (index == shndx) return @intCast(self.output_sections.keys().len + 1);
|
||||
}
|
||||
const base: usize = if (self.eh_frame_section_index == null) 0 else 1;
|
||||
for (self.merge_sections.items, 0..) |msec, index| {
|
||||
if (msec.output_section_index == shndx) return @intCast(self.output_sections.keys().len + 1 + index + base);
|
||||
}
|
||||
return @intCast(self.output_sections.getIndex(shndx).? + 1);
|
||||
}
|
||||
|
||||
|
|
@ -5537,10 +5501,11 @@ fn formatShdr(
|
|||
_ = options;
|
||||
_ = unused_fmt_string;
|
||||
const shdr = ctx.shdr;
|
||||
try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : flags({})", .{
|
||||
try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : entsize({x}) : flags({})", .{
|
||||
ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
|
||||
shdr.sh_addr, shdr.sh_addralign,
|
||||
shdr.sh_size, fmtShdrFlags(shdr.sh_flags),
|
||||
shdr.sh_size, shdr.sh_entsize,
|
||||
fmtShdrFlags(shdr.sh_flags),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
|
|||
try dwarf.resolveRelocs();
|
||||
|
||||
const gpa = elf_file.base.comp.gpa;
|
||||
const cpu_arch = elf_file.getTarget().cpu.arch;
|
||||
|
||||
// TODO invert this logic so that we manage the output section with the atom, not the
|
||||
// other way around
|
||||
|
|
@ -242,20 +243,17 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
|
|||
target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
|
||||
else
|
||||
0));
|
||||
const r_type: elf.R_X86_64 = switch (dwarf.format) {
|
||||
.@"32" => .@"32",
|
||||
.@"64" => .@"64",
|
||||
};
|
||||
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(@intFromEnum(r_type), elf_file.getTarget().cpu.arch),
|
||||
relocation.fmtRelocType(r_type, cpu_arch),
|
||||
});
|
||||
atom_ptr.addRelocAssumeCapacity(.{
|
||||
.r_offset = r_offset,
|
||||
.r_addend = r_addend,
|
||||
.r_info = (@as(u64, @intCast(target_sym_index)) << 32) | @intFromEnum(r_type),
|
||||
.r_info = (@as(u64, @intCast(target_sym_index)) << 32) | r_type,
|
||||
}, self);
|
||||
}
|
||||
|
||||
|
|
@ -264,21 +262,17 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
|
|||
const target_sym = self.symbol(reloc.target_sym);
|
||||
const r_offset = unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off;
|
||||
const r_addend: i64 = @intCast(reloc.target_off);
|
||||
const r_type: elf.R_X86_64 = switch (dwarf.address_size) {
|
||||
.@"32" => if (target_sym.flags.is_tls) .DTPOFF32 else .@"32",
|
||||
.@"64" => if (target_sym.flags.is_tls) .DTPOFF64 else .@"64",
|
||||
else => unreachable,
|
||||
};
|
||||
const r_type = relocation.dwarf.externalRelocType(target_sym.*, 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(@intFromEnum(r_type), elf_file.getTarget().cpu.arch),
|
||||
relocation.fmtRelocType(r_type, cpu_arch),
|
||||
});
|
||||
atom_ptr.addRelocAssumeCapacity(.{
|
||||
.r_offset = r_offset,
|
||||
.r_addend = r_addend,
|
||||
.r_info = (@as(u64, @intCast(reloc.target_sym)) << 32) | @intFromEnum(r_type),
|
||||
.r_info = (@as(u64, @intCast(reloc.target_sym)) << 32) | r_type,
|
||||
}, self);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
pub const MergeSection = struct {
|
||||
value: u64 = 0,
|
||||
size: u64 = 0,
|
||||
alignment: Atom.Alignment = .@"1",
|
||||
entsize: u32 = 0,
|
||||
name_offset: u32 = 0,
|
||||
type: u32 = 0,
|
||||
flags: u64 = 0,
|
||||
|
|
@ -26,7 +30,7 @@ pub const MergeSection = struct {
|
|||
|
||||
pub fn address(msec: MergeSection, elf_file: *Elf) i64 {
|
||||
const shdr = elf_file.shdrs.items[msec.output_section_index];
|
||||
return @intCast(shdr.sh_addr);
|
||||
return @intCast(shdr.sh_addr + msec.value);
|
||||
}
|
||||
|
||||
const InsertResult = struct {
|
||||
|
|
@ -90,6 +94,29 @@ pub const MergeSection = struct {
|
|||
std.mem.sort(MergeSubsection.Index, msec.finalized_subsections.items, msec, sortFn);
|
||||
}
|
||||
|
||||
pub fn updateSize(msec: *MergeSection) void {
|
||||
for (msec.finalized_subsections.items) |msub_index| {
|
||||
const msub = msec.mergeSubsection(msub_index);
|
||||
assert(msub.alive);
|
||||
const offset = msub.alignment.forward(msec.size);
|
||||
const padding = offset - msec.size;
|
||||
msub.value = @intCast(offset);
|
||||
msec.size += padding + msub.size;
|
||||
msec.alignment = msec.alignment.max(msub.alignment);
|
||||
msec.entsize = if (msec.entsize == 0) msub.entsize else @min(msec.entsize, msub.entsize);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initOutputSection(msec: *MergeSection, elf_file: *Elf) !void {
|
||||
const shndx = elf_file.sectionByName(msec.name(elf_file)) orelse try elf_file.addSection(.{
|
||||
.name = msec.name_offset,
|
||||
.type = msec.type,
|
||||
.flags = msec.flags,
|
||||
});
|
||||
try elf_file.output_sections.put(elf_file.base.comp.gpa, shndx, .{});
|
||||
msec.output_section_index = shndx;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -163,9 +190,12 @@ pub const MergeSection = struct {
|
|||
_ = unused_fmt_string;
|
||||
const msec = ctx.msec;
|
||||
const elf_file = ctx.elf_file;
|
||||
try writer.print("{s} : @{x} : type({x}) : flags({x})\n", .{
|
||||
try writer.print("{s} : @{x} : size({x}) : align({x}) : entsize({x}) : type({x}) : flags({x})\n", .{
|
||||
msec.name(elf_file),
|
||||
msec.address(elf_file),
|
||||
msec.size,
|
||||
msec.alignment.toByteUnits() orelse 0,
|
||||
msec.entsize,
|
||||
msec.type,
|
||||
msec.flags,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -42,7 +42,11 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
|
|||
try elf_file.finalizeMergeSections();
|
||||
zig_object.claimUnresolvedObject(elf_file);
|
||||
|
||||
try elf_file.initMergeSections();
|
||||
for (elf_file.merge_sections.items) |*msec| {
|
||||
if (msec.finalized_subsections.items.len == 0) continue;
|
||||
try msec.initOutputSection(elf_file);
|
||||
}
|
||||
|
||||
try elf_file.initSymtab();
|
||||
try elf_file.initShStrtab();
|
||||
try elf_file.sortShdrs();
|
||||
|
|
@ -198,7 +202,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
|
|||
claimUnresolved(elf_file);
|
||||
|
||||
try initSections(elf_file);
|
||||
try elf_file.initMergeSections();
|
||||
try elf_file.sortShdrs();
|
||||
if (elf_file.zigObjectPtr()) |zig_object| {
|
||||
try zig_object.addAtomsToRelaSections(elf_file);
|
||||
|
|
@ -294,6 +297,11 @@ fn initSections(elf_file: *Elf) !void {
|
|||
try object.initRelaSections(elf_file);
|
||||
}
|
||||
|
||||
for (elf_file.merge_sections.items) |*msec| {
|
||||
if (msec.finalized_subsections.items.len == 0) continue;
|
||||
try msec.initOutputSection(elf_file);
|
||||
}
|
||||
|
||||
const needs_eh_frame = for (elf_file.objects.items) |index| {
|
||||
if (elf_file.file(index).?.object.cies.items.len > 0) break true;
|
||||
} else false;
|
||||
|
|
|
|||
|
|
@ -91,6 +91,44 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 {
|
|||
};
|
||||
}
|
||||
|
||||
pub const dwarf = struct {
|
||||
pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 {
|
||||
return switch (cpu_arch) {
|
||||
.x86_64 => @intFromEnum(switch (format) {
|
||||
.@"32" => elf.R_X86_64.@"32",
|
||||
.@"64" => .@"64",
|
||||
}),
|
||||
.riscv64 => @intFromEnum(switch (format) {
|
||||
.@"32" => elf.R_RISCV.@"32",
|
||||
.@"64" => .@"64",
|
||||
}),
|
||||
else => @panic("TODO unhandled cpu arch"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn externalRelocType(
|
||||
target: Symbol,
|
||||
address_size: Dwarf.AddressSize,
|
||||
cpu_arch: std.Target.Cpu.Arch,
|
||||
) u32 {
|
||||
return switch (cpu_arch) {
|
||||
.x86_64 => @intFromEnum(switch (address_size) {
|
||||
.@"32" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF32 else .@"32",
|
||||
.@"64" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF64 else .@"64",
|
||||
else => unreachable,
|
||||
}),
|
||||
.riscv64 => @intFromEnum(switch (address_size) {
|
||||
.@"32" => elf.R_RISCV.@"32",
|
||||
.@"64" => elf.R_RISCV.@"64",
|
||||
else => unreachable,
|
||||
}),
|
||||
else => @panic("TODO unhandled cpu arch"),
|
||||
};
|
||||
}
|
||||
|
||||
const DW = std.dwarf;
|
||||
};
|
||||
|
||||
const FormatRelocTypeCtx = struct {
|
||||
r_type: u32,
|
||||
cpu_arch: std.Target.Cpu.Arch,
|
||||
|
|
@ -124,4 +162,6 @@ const assert = std.debug.assert;
|
|||
const elf = std.elf;
|
||||
const std = @import("std");
|
||||
|
||||
const Dwarf = @import("../Dwarf.zig");
|
||||
const Elf = @import("../Elf.zig");
|
||||
const Symbol = @import("Symbol.zig");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue