authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-08-20 14:34:31+02:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-08-21 01:43:21-04:00
log6c731be3a1710f3c70a955624c30467616f1d1c0
treec5c263743d1dd630977ea07903a89a89bb76259b
parentb2fad5c58bfe2c8b013a5720c509b792e227415c

elf: allow for concatenating atoms to merge sections


5 files changed, 105 insertions(+), 68 deletions(-)

src/link/Elf.zig+16-51
......@@ -1282,7 +1282,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
12821282 try self.addCommentString();
12831283 try self.finalizeMergeSections();
12841284 try self.initOutputSections();
1285 try self.initMergeSections();
12861285 if (self.linkerDefinedPtr()) |obj| {
12871286 try obj.initStartStopSymbols(self);
12881287 }
......@@ -3048,17 +3047,17 @@ pub fn finalizeMergeSections(self: *Elf) !void {
30483047}
30493048
30503049pub fn updateMergeSectionSizes(self: *Elf) !void {
3050 for (self.merge_sections.items) |*msec| {
3051 msec.updateSize();
3052 }
30513053 for (self.merge_sections.items) |*msec| {
30523054 const shdr = &self.shdrs.items[msec.output_section_index];
3053 for (msec.finalized_subsections.items) |msub_index| {
3054 const msub = msec.mergeSubsection(msub_index);
3055 assert(msub.alive);
3056 const offset = msub.alignment.forward(shdr.sh_size);
3057 const padding = offset - shdr.sh_size;
3058 msub.value = @intCast(offset);
3059 shdr.sh_size += padding + msub.size;
3060 shdr.sh_addralign = @max(shdr.sh_addralign, msub.alignment.toByteUnits() orelse 1);
3061 }
3055 const offset = msec.alignment.forward(shdr.sh_size);
3056 const padding = offset - shdr.sh_size;
3057 msec.value = @intCast(offset);
3058 shdr.sh_size += padding + msec.size;
3059 shdr.sh_addralign = @max(shdr.sh_addralign, msec.alignment.toByteUnits() orelse 1);
3060 shdr.sh_entsize = if (shdr.sh_entsize == 0) msec.entsize else @min(shdr.sh_entsize, msec.entsize);
30623061 }
30633062}
30643063
......@@ -3069,7 +3068,8 @@ pub fn writeMergeSections(self: *Elf) !void {
30693068
30703069 for (self.merge_sections.items) |*msec| {
30713070 const shdr = self.shdrs.items[msec.output_section_index];
3072 const size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
3071 const fileoff = math.cast(usize, msec.value + shdr.sh_offset) orelse return error.Overflow;
3072 const size = math.cast(usize, msec.size) orelse return error.Overflow;
30733073 try buffer.ensureTotalCapacity(size);
30743074 buffer.appendNTimesAssumeCapacity(0, size);
30753075
......@@ -3081,7 +3081,7 @@ pub fn writeMergeSections(self: *Elf) !void {
30813081 @memcpy(buffer.items[off..][0..string.len], string);
30823082 }
30833083
3084 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
3084 try self.base.file.?.pwriteAll(buffer.items, fileoff);
30853085 buffer.clearRetainingCapacity();
30863086 }
30873087}
......@@ -3090,26 +3090,9 @@ fn initOutputSections(self: *Elf) !void {
30903090 for (self.objects.items) |index| {
30913091 try self.file(index).?.object.initOutputSections(self);
30923092 }
3093}
3094
3095pub fn initMergeSections(self: *Elf) !void {
30963093 for (self.merge_sections.items) |*msec| {
30973094 if (msec.finalized_subsections.items.len == 0) continue;
3098 const name = msec.name(self);
3099 const shndx = self.sectionByName(name) orelse try self.addSection(.{
3100 .name = msec.name_offset,
3101 .type = msec.type,
3102 .flags = msec.flags,
3103 });
3104 msec.output_section_index = shndx;
3105
3106 var entsize = msec.mergeSubsection(msec.finalized_subsections.items[0]).entsize;
3107 for (msec.finalized_subsections.items) |msub_index| {
3108 const msub = msec.mergeSubsection(msub_index);
3109 entsize = @min(entsize, msub.entsize);
3110 }
3111 const shdr = &self.shdrs.items[shndx];
3112 shdr.sh_entsize = entsize;
3095 try msec.initOutputSection(self);
31133096 }
31143097}
31153098
......@@ -4427,7 +4410,6 @@ pub fn updateSymtabSize(self: *Elf) !void {
44274410 if (self.eh_frame_section_index) |_| {
44284411 nlocals += 1;
44294412 }
4430 nlocals += @intCast(self.merge_sections.items.len);
44314413
44324414 if (self.requiresThunks()) for (self.thunks.items) |*th| {
44334415 th.output_symtab_ctx.ilocal = nlocals + 1;
......@@ -4751,30 +4733,12 @@ fn writeSectionSymbols(self: *Elf) void {
47514733 };
47524734 ilocal += 1;
47534735 }
4754
4755 for (self.merge_sections.items) |msec| {
4756 const shdr = self.shdrs.items[msec.output_section_index];
4757 const out_sym = &self.symtab.items[ilocal];
4758 out_sym.* = .{
4759 .st_name = 0,
4760 .st_value = shdr.sh_addr,
4761 .st_info = elf.STT_SECTION,
4762 .st_shndx = @intCast(msec.output_section_index),
4763 .st_size = 0,
4764 .st_other = 0,
4765 };
4766 ilocal += 1;
4767 }
47684736}
47694737
47704738pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 {
47714739 if (self.eh_frame_section_index) |index| {
47724740 if (index == shndx) return @intCast(self.output_sections.keys().len + 1);
47734741 }
4774 const base: usize = if (self.eh_frame_section_index == null) 0 else 1;
4775 for (self.merge_sections.items, 0..) |msec, index| {
4776 if (msec.output_section_index == shndx) return @intCast(self.output_sections.keys().len + 1 + index + base);
4777 }
47784742 return @intCast(self.output_sections.getIndex(shndx).? + 1);
47794743}
47804744
......@@ -5537,10 +5501,11 @@ fn formatShdr(
55375501 _ = options;
55385502 _ = unused_fmt_string;
55395503 const shdr = ctx.shdr;
5540 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : flags({})", .{
5504 try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : entsize({x}) : flags({})", .{
55415505 ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
55425506 shdr.sh_addr, shdr.sh_addralign,
5543 shdr.sh_size, fmtShdrFlags(shdr.sh_flags),
5507 shdr.sh_size, shdr.sh_entsize,
5508 fmtShdrFlags(shdr.sh_flags),
55445509 });
55455510}
55465511
src/link/Elf/ZigObject.zig+7-13
......@@ -183,6 +183,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
183183 try dwarf.resolveRelocs();
184184
185185 const gpa = elf_file.base.comp.gpa;
186 const cpu_arch = elf_file.getTarget().cpu.arch;
186187
187188 // TODO invert this logic so that we manage the output section with the atom, not the
188189 // other way around
......@@ -242,20 +243,17 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
242243 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
243244 else
244245 0));
245 const r_type: elf.R_X86_64 = switch (dwarf.format) {
246 .@"32" => .@"32",
247 .@"64" => .@"64",
248 };
246 const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
249247 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
250248 self.symbol(target_sym_index).name(elf_file),
251249 r_offset,
252250 r_addend,
253 relocation.fmtRelocType(@intFromEnum(r_type), elf_file.getTarget().cpu.arch),
251 relocation.fmtRelocType(r_type, cpu_arch),
254252 });
255253 atom_ptr.addRelocAssumeCapacity(.{
256254 .r_offset = r_offset,
257255 .r_addend = r_addend,
258 .r_info = (@as(u64, @intCast(target_sym_index)) << 32) | @intFromEnum(r_type),
256 .r_info = (@as(u64, @intCast(target_sym_index)) << 32) | r_type,
259257 }, self);
260258 }
261259
......@@ -264,21 +262,17 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
264262 const target_sym = self.symbol(reloc.target_sym);
265263 const r_offset = unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off;
266264 const r_addend: i64 = @intCast(reloc.target_off);
267 const r_type: elf.R_X86_64 = switch (dwarf.address_size) {
268 .@"32" => if (target_sym.flags.is_tls) .DTPOFF32 else .@"32",
269 .@"64" => if (target_sym.flags.is_tls) .DTPOFF64 else .@"64",
270 else => unreachable,
271 };
265 const r_type = relocation.dwarf.externalRelocType(target_sym.*, dwarf.address_size, cpu_arch);
272266 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
273267 target_sym.name(elf_file),
274268 r_offset,
275269 r_addend,
276 relocation.fmtRelocType(@intFromEnum(r_type), elf_file.getTarget().cpu.arch),
270 relocation.fmtRelocType(r_type, cpu_arch),
277271 });
278272 atom_ptr.addRelocAssumeCapacity(.{
279273 .r_offset = r_offset,
280274 .r_addend = r_addend,
281 .r_info = (@as(u64, @intCast(reloc.target_sym)) << 32) | @intFromEnum(r_type),
275 .r_info = (@as(u64, @intCast(reloc.target_sym)) << 32) | r_type,
282276 }, self);
283277 }
284278 }
src/link/Elf/merge_section.zig+32-2
......@@ -1,4 +1,8 @@
11pub const MergeSection = struct {
2 value: u64 = 0,
3 size: u64 = 0,
4 alignment: Atom.Alignment = .@"1",
5 entsize: u32 = 0,
26 name_offset: u32 = 0,
37 type: u32 = 0,
48 flags: u64 = 0,
......@@ -26,7 +30,7 @@ pub const MergeSection = struct {
2630
2731 pub fn address(msec: MergeSection, elf_file: *Elf) i64 {
2832 const shdr = elf_file.shdrs.items[msec.output_section_index];
29 return @intCast(shdr.sh_addr);
33 return @intCast(shdr.sh_addr + msec.value);
3034 }
3135
3236 const InsertResult = struct {
......@@ -90,6 +94,29 @@ pub const MergeSection = struct {
9094 std.mem.sort(MergeSubsection.Index, msec.finalized_subsections.items, msec, sortFn);
9195 }
9296
97 pub fn updateSize(msec: *MergeSection) void {
98 for (msec.finalized_subsections.items) |msub_index| {
99 const msub = msec.mergeSubsection(msub_index);
100 assert(msub.alive);
101 const offset = msub.alignment.forward(msec.size);
102 const padding = offset - msec.size;
103 msub.value = @intCast(offset);
104 msec.size += padding + msub.size;
105 msec.alignment = msec.alignment.max(msub.alignment);
106 msec.entsize = if (msec.entsize == 0) msub.entsize else @min(msec.entsize, msub.entsize);
107 }
108 }
109
110 pub fn initOutputSection(msec: *MergeSection, elf_file: *Elf) !void {
111 const shndx = elf_file.sectionByName(msec.name(elf_file)) orelse try elf_file.addSection(.{
112 .name = msec.name_offset,
113 .type = msec.type,
114 .flags = msec.flags,
115 });
116 try elf_file.output_sections.put(elf_file.base.comp.gpa, shndx, .{});
117 msec.output_section_index = shndx;
118 }
119
93120 pub fn addMergeSubsection(msec: *MergeSection, allocator: Allocator) !MergeSubsection.Index {
94121 const index: MergeSubsection.Index = @intCast(msec.subsections.items.len);
95122 const msub = try msec.subsections.addOne(allocator);
......@@ -163,9 +190,12 @@ pub const MergeSection = struct {
163190 _ = unused_fmt_string;
164191 const msec = ctx.msec;
165192 const elf_file = ctx.elf_file;
166 try writer.print("{s} : @{x} : type({x}) : flags({x})\n", .{
193 try writer.print("{s} : @{x} : size({x}) : align({x}) : entsize({x}) : type({x}) : flags({x})\n", .{
167194 msec.name(elf_file),
168195 msec.address(elf_file),
196 msec.size,
197 msec.alignment.toByteUnits() orelse 0,
198 msec.entsize,
169199 msec.type,
170200 msec.flags,
171201 });
src/link/Elf/relocatable.zig+10-2
......@@ -42,7 +42,11 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
4242 try elf_file.finalizeMergeSections();
4343 zig_object.claimUnresolvedObject(elf_file);
4444
45 try elf_file.initMergeSections();
45 for (elf_file.merge_sections.items) |*msec| {
46 if (msec.finalized_subsections.items.len == 0) continue;
47 try msec.initOutputSection(elf_file);
48 }
49
4650 try elf_file.initSymtab();
4751 try elf_file.initShStrtab();
4852 try elf_file.sortShdrs();
......@@ -198,7 +202,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
198202 claimUnresolved(elf_file);
199203
200204 try initSections(elf_file);
201 try elf_file.initMergeSections();
202205 try elf_file.sortShdrs();
203206 if (elf_file.zigObjectPtr()) |zig_object| {
204207 try zig_object.addAtomsToRelaSections(elf_file);
......@@ -294,6 +297,11 @@ fn initSections(elf_file: *Elf) !void {
294297 try object.initRelaSections(elf_file);
295298 }
296299
300 for (elf_file.merge_sections.items) |*msec| {
301 if (msec.finalized_subsections.items.len == 0) continue;
302 try msec.initOutputSection(elf_file);
303 }
304
297305 const needs_eh_frame = for (elf_file.objects.items) |index| {
298306 if (elf_file.file(index).?.object.cies.items.len > 0) break true;
299307 } else false;
src/link/Elf/relocation.zig+40
......@@ -91,6 +91,44 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 {
9191 };
9292}
9393
94pub const dwarf = struct {
95 pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 {
96 return switch (cpu_arch) {
97 .x86_64 => @intFromEnum(switch (format) {
98 .@"32" => elf.R_X86_64.@"32",
99 .@"64" => .@"64",
100 }),
101 .riscv64 => @intFromEnum(switch (format) {
102 .@"32" => elf.R_RISCV.@"32",
103 .@"64" => .@"64",
104 }),
105 else => @panic("TODO unhandled cpu arch"),
106 };
107 }
108
109 pub fn externalRelocType(
110 target: Symbol,
111 address_size: Dwarf.AddressSize,
112 cpu_arch: std.Target.Cpu.Arch,
113 ) u32 {
114 return switch (cpu_arch) {
115 .x86_64 => @intFromEnum(switch (address_size) {
116 .@"32" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF32 else .@"32",
117 .@"64" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF64 else .@"64",
118 else => unreachable,
119 }),
120 .riscv64 => @intFromEnum(switch (address_size) {
121 .@"32" => elf.R_RISCV.@"32",
122 .@"64" => elf.R_RISCV.@"64",
123 else => unreachable,
124 }),
125 else => @panic("TODO unhandled cpu arch"),
126 };
127 }
128
129 const DW = std.dwarf;
130};
131
94132const FormatRelocTypeCtx = struct {
95133 r_type: u32,
96134 cpu_arch: std.Target.Cpu.Arch,
......@@ -124,4 +162,6 @@ const assert = std.debug.assert;
124162const elf = std.elf;
125163const std = @import("std");
126164
165const Dwarf = @import("../Dwarf.zig");
127166const Elf = @import("../Elf.zig");
167const Symbol = @import("Symbol.zig");