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...@@ -1282,7 +1282,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1282 try self.addCommentString();1282 try self.addCommentString();
1283 try self.finalizeMergeSections();1283 try self.finalizeMergeSections();
1284 try self.initOutputSections();1284 try self.initOutputSections();
1285 try self.initMergeSections();
1286 if (self.linkerDefinedPtr()) |obj| {1285 if (self.linkerDefinedPtr()) |obj| {
1287 try obj.initStartStopSymbols(self);1286 try obj.initStartStopSymbols(self);
1288 }1287 }
...@@ -3048,17 +3047,17 @@ pub fn finalizeMergeSections(self: *Elf) !void {...@@ -3048,17 +3047,17 @@ pub fn finalizeMergeSections(self: *Elf) !void {
3048}3047}
30493048
3050pub fn updateMergeSectionSizes(self: *Elf) !void {3049pub fn updateMergeSectionSizes(self: *Elf) !void {
3050 for (self.merge_sections.items) |*msec| {
3051 msec.updateSize();
3052 }
3051 for (self.merge_sections.items) |*msec| {3053 for (self.merge_sections.items) |*msec| {
3052 const shdr = &self.shdrs.items[msec.output_section_index];3054 const shdr = &self.shdrs.items[msec.output_section_index];
3053 for (msec.finalized_subsections.items) |msub_index| {3055 const offset = msec.alignment.forward(shdr.sh_size);
3054 const msub = msec.mergeSubsection(msub_index);3056 const padding = offset - shdr.sh_size;
3055 assert(msub.alive);3057 msec.value = @intCast(offset);
3056 const offset = msub.alignment.forward(shdr.sh_size);3058 shdr.sh_size += padding + msec.size;
3057 const padding = offset - shdr.sh_size;3059 shdr.sh_addralign = @max(shdr.sh_addralign, msec.alignment.toByteUnits() orelse 1);
3058 msub.value = @intCast(offset);3060 shdr.sh_entsize = if (shdr.sh_entsize == 0) msec.entsize else @min(shdr.sh_entsize, msec.entsize);
3059 shdr.sh_size += padding + msub.size;
3060 shdr.sh_addralign = @max(shdr.sh_addralign, msub.alignment.toByteUnits() orelse 1);
3061 }
3062 }3061 }
3063}3062}
30643063
...@@ -3069,7 +3068,8 @@ pub fn writeMergeSections(self: *Elf) !void {...@@ -3069,7 +3068,8 @@ pub fn writeMergeSections(self: *Elf) !void {
30693068
3070 for (self.merge_sections.items) |*msec| {3069 for (self.merge_sections.items) |*msec| {
3071 const shdr = self.shdrs.items[msec.output_section_index];3070 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;
3073 try buffer.ensureTotalCapacity(size);3073 try buffer.ensureTotalCapacity(size);
3074 buffer.appendNTimesAssumeCapacity(0, size);3074 buffer.appendNTimesAssumeCapacity(0, size);
30753075
...@@ -3081,7 +3081,7 @@ pub fn writeMergeSections(self: *Elf) !void {...@@ -3081,7 +3081,7 @@ pub fn writeMergeSections(self: *Elf) !void {
3081 @memcpy(buffer.items[off..][0..string.len], string);3081 @memcpy(buffer.items[off..][0..string.len], string);
3082 }3082 }
30833083
3084 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);3084 try self.base.file.?.pwriteAll(buffer.items, fileoff);
3085 buffer.clearRetainingCapacity();3085 buffer.clearRetainingCapacity();
3086 }3086 }
3087}3087}
...@@ -3090,26 +3090,9 @@ fn initOutputSections(self: *Elf) !void {...@@ -3090,26 +3090,9 @@ fn initOutputSections(self: *Elf) !void {
3090 for (self.objects.items) |index| {3090 for (self.objects.items) |index| {
3091 try self.file(index).?.object.initOutputSections(self);3091 try self.file(index).?.object.initOutputSections(self);
3092 }3092 }
3093}
3094
3095pub fn initMergeSections(self: *Elf) !void {
3096 for (self.merge_sections.items) |*msec| {3093 for (self.merge_sections.items) |*msec| {
3097 if (msec.finalized_subsections.items.len == 0) continue;3094 if (msec.finalized_subsections.items.len == 0) continue;
3098 const name = msec.name(self);3095 try msec.initOutputSection(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;
3113 }3096 }
3114}3097}
31153098
...@@ -4427,7 +4410,6 @@ pub fn updateSymtabSize(self: *Elf) !void {...@@ -4427,7 +4410,6 @@ pub fn updateSymtabSize(self: *Elf) !void {
4427 if (self.eh_frame_section_index) |_| {4410 if (self.eh_frame_section_index) |_| {
4428 nlocals += 1;4411 nlocals += 1;
4429 }4412 }
4430 nlocals += @intCast(self.merge_sections.items.len);
44314413
4432 if (self.requiresThunks()) for (self.thunks.items) |*th| {4414 if (self.requiresThunks()) for (self.thunks.items) |*th| {
4433 th.output_symtab_ctx.ilocal = nlocals + 1;4415 th.output_symtab_ctx.ilocal = nlocals + 1;
...@@ -4751,30 +4733,12 @@ fn writeSectionSymbols(self: *Elf) void {...@@ -4751,30 +4733,12 @@ fn writeSectionSymbols(self: *Elf) void {
4751 };4733 };
4752 ilocal += 1;4734 ilocal += 1;
4753 }4735 }
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 }
4768}4736}
47694737
4770pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 {4738pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 {
4771 if (self.eh_frame_section_index) |index| {4739 if (self.eh_frame_section_index) |index| {
4772 if (index == shndx) return @intCast(self.output_sections.keys().len + 1);4740 if (index == shndx) return @intCast(self.output_sections.keys().len + 1);
4773 }4741 }
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 }
4778 return @intCast(self.output_sections.getIndex(shndx).? + 1);4742 return @intCast(self.output_sections.getIndex(shndx).? + 1);
4779}4743}
47804744
...@@ -5537,10 +5501,11 @@ fn formatShdr(...@@ -5537,10 +5501,11 @@ fn formatShdr(
5537 _ = options;5501 _ = options;
5538 _ = unused_fmt_string;5502 _ = unused_fmt_string;
5539 const shdr = ctx.shdr;5503 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({})", .{
5541 ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,5505 ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
5542 shdr.sh_addr, shdr.sh_addralign,5506 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),
5544 });5509 });
5545}5510}
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...@@ -183,6 +183,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
183 try dwarf.resolveRelocs();183 try dwarf.resolveRelocs();
184184
185 const gpa = elf_file.base.comp.gpa;185 const gpa = elf_file.base.comp.gpa;
186 const cpu_arch = elf_file.getTarget().cpu.arch;
186187
187 // TODO invert this logic so that we manage the output section with the atom, not the188 // TODO invert this logic so that we manage the output section with the atom, not the
188 // other way around189 // other way around
...@@ -242,20 +243,17 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -242,20 +243,17 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
242 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off243 target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
243 else244 else
244 0));245 0));
245 const r_type: elf.R_X86_64 = switch (dwarf.format) {246 const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
246 .@"32" => .@"32",
247 .@"64" => .@"64",
248 };
249 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{247 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
250 self.symbol(target_sym_index).name(elf_file),248 self.symbol(target_sym_index).name(elf_file),
251 r_offset,249 r_offset,
252 r_addend,250 r_addend,
253 relocation.fmtRelocType(@intFromEnum(r_type), elf_file.getTarget().cpu.arch),251 relocation.fmtRelocType(r_type, cpu_arch),
254 });252 });
255 atom_ptr.addRelocAssumeCapacity(.{253 atom_ptr.addRelocAssumeCapacity(.{
256 .r_offset = r_offset,254 .r_offset = r_offset,
257 .r_addend = r_addend,255 .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,
259 }, self);257 }, self);
260 }258 }
261259
...@@ -264,21 +262,17 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -264,21 +262,17 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
264 const target_sym = self.symbol(reloc.target_sym);262 const target_sym = self.symbol(reloc.target_sym);
265 const r_offset = unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off;263 const r_offset = unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off;
266 const r_addend: i64 = @intCast(reloc.target_off);264 const r_addend: i64 = @intCast(reloc.target_off);
267 const r_type: elf.R_X86_64 = switch (dwarf.address_size) {265 const r_type = relocation.dwarf.externalRelocType(target_sym.*, dwarf.address_size, cpu_arch);
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 };
272 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{266 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
273 target_sym.name(elf_file),267 target_sym.name(elf_file),
274 r_offset,268 r_offset,
275 r_addend,269 r_addend,
276 relocation.fmtRelocType(@intFromEnum(r_type), elf_file.getTarget().cpu.arch),270 relocation.fmtRelocType(r_type, cpu_arch),
277 });271 });
278 atom_ptr.addRelocAssumeCapacity(.{272 atom_ptr.addRelocAssumeCapacity(.{
279 .r_offset = r_offset,273 .r_offset = r_offset,
280 .r_addend = r_addend,274 .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,
282 }, self);276 }, self);
283 }277 }
284 }278 }
src/link/Elf/merge_section.zig+32-2
...@@ -1,4 +1,8 @@...@@ -1,4 +1,8 @@
1pub const MergeSection = struct {1pub const MergeSection = struct {
2 value: u64 = 0,
3 size: u64 = 0,
4 alignment: Atom.Alignment = .@"1",
5 entsize: u32 = 0,
2 name_offset: u32 = 0,6 name_offset: u32 = 0,
3 type: u32 = 0,7 type: u32 = 0,
4 flags: u64 = 0,8 flags: u64 = 0,
...@@ -26,7 +30,7 @@ pub const MergeSection = struct {...@@ -26,7 +30,7 @@ pub const MergeSection = struct {
2630
27 pub fn address(msec: MergeSection, elf_file: *Elf) i64 {31 pub fn address(msec: MergeSection, elf_file: *Elf) i64 {
28 const shdr = elf_file.shdrs.items[msec.output_section_index];32 const shdr = elf_file.shdrs.items[msec.output_section_index];
29 return @intCast(shdr.sh_addr);33 return @intCast(shdr.sh_addr + msec.value);
30 }34 }
3135
32 const InsertResult = struct {36 const InsertResult = struct {
...@@ -90,6 +94,29 @@ pub const MergeSection = struct {...@@ -90,6 +94,29 @@ pub const MergeSection = struct {
90 std.mem.sort(MergeSubsection.Index, msec.finalized_subsections.items, msec, sortFn);94 std.mem.sort(MergeSubsection.Index, msec.finalized_subsections.items, msec, sortFn);
91 }95 }
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
93 pub fn addMergeSubsection(msec: *MergeSection, allocator: Allocator) !MergeSubsection.Index {120 pub fn addMergeSubsection(msec: *MergeSection, allocator: Allocator) !MergeSubsection.Index {
94 const index: MergeSubsection.Index = @intCast(msec.subsections.items.len);121 const index: MergeSubsection.Index = @intCast(msec.subsections.items.len);
95 const msub = try msec.subsections.addOne(allocator);122 const msub = try msec.subsections.addOne(allocator);
...@@ -163,9 +190,12 @@ pub const MergeSection = struct {...@@ -163,9 +190,12 @@ pub const MergeSection = struct {
163 _ = unused_fmt_string;190 _ = unused_fmt_string;
164 const msec = ctx.msec;191 const msec = ctx.msec;
165 const elf_file = ctx.elf_file;192 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", .{
167 msec.name(elf_file),194 msec.name(elf_file),
168 msec.address(elf_file),195 msec.address(elf_file),
196 msec.size,
197 msec.alignment.toByteUnits() orelse 0,
198 msec.entsize,
169 msec.type,199 msec.type,
170 msec.flags,200 msec.flags,
171 });201 });
src/link/Elf/relocatable.zig+10-2
...@@ -42,7 +42,11 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co...@@ -42,7 +42,11 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
42 try elf_file.finalizeMergeSections();42 try elf_file.finalizeMergeSections();
43 zig_object.claimUnresolvedObject(elf_file);43 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
46 try elf_file.initSymtab();50 try elf_file.initSymtab();
47 try elf_file.initShStrtab();51 try elf_file.initShStrtab();
48 try elf_file.sortShdrs();52 try elf_file.sortShdrs();
...@@ -198,7 +202,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const...@@ -198,7 +202,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
198 claimUnresolved(elf_file);202 claimUnresolved(elf_file);
199203
200 try initSections(elf_file);204 try initSections(elf_file);
201 try elf_file.initMergeSections();
202 try elf_file.sortShdrs();205 try elf_file.sortShdrs();
203 if (elf_file.zigObjectPtr()) |zig_object| {206 if (elf_file.zigObjectPtr()) |zig_object| {
204 try zig_object.addAtomsToRelaSections(elf_file);207 try zig_object.addAtomsToRelaSections(elf_file);
...@@ -294,6 +297,11 @@ fn initSections(elf_file: *Elf) !void {...@@ -294,6 +297,11 @@ fn initSections(elf_file: *Elf) !void {
294 try object.initRelaSections(elf_file);297 try object.initRelaSections(elf_file);
295 }298 }
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
297 const needs_eh_frame = for (elf_file.objects.items) |index| {305 const needs_eh_frame = for (elf_file.objects.items) |index| {
298 if (elf_file.file(index).?.object.cies.items.len > 0) break true;306 if (elf_file.file(index).?.object.cies.items.len > 0) break true;
299 } else false;307 } 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 {...@@ -91,6 +91,44 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 {
91 };91 };
92}92}
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
94const FormatRelocTypeCtx = struct {132const FormatRelocTypeCtx = struct {
95 r_type: u32,133 r_type: u32,
96 cpu_arch: std.Target.Cpu.Arch,134 cpu_arch: std.Target.Cpu.Arch,
...@@ -124,4 +162,6 @@ const assert = std.debug.assert;...@@ -124,4 +162,6 @@ const assert = std.debug.assert;
124const elf = std.elf;162const elf = std.elf;
125const std = @import("std");163const std = @import("std");
126164
165const Dwarf = @import("../Dwarf.zig");
127const Elf = @import("../Elf.zig");166const Elf = @import("../Elf.zig");
167const Symbol = @import("Symbol.zig");