Commit 6c731be3a1
Changed files (5)
src/link/Elf/merge_section.zig
@@ -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,
});
src/link/Elf/relocatable.zig
@@ -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;
src/link/Elf/relocation.zig
@@ -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");
src/link/Elf/ZigObject.zig
@@ -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);
}
}
src/link/Elf.zig
@@ -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),
});
}