diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 4c53898df8..a72c96c51e 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -1664,6 +1664,8 @@ pub const EM = enum(u16) { } }; +pub const GRP_COMDAT = 1; + /// Section data should be writable during execution. pub const SHF_WRITE = 0x1; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 0753869671..678844aa81 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -102,6 +102,9 @@ copy_rel: CopyRelSection = .{}, rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, /// .got.zig section zig_got: ZigGotSection = .{}, +/// SHT_GROUP sections +/// Applies only to a relocatable. +comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, /// Tracked section headers with incremental updates to Zig object. /// .rela.* sections are only used when emitting a relocatable object file. @@ -394,6 +397,7 @@ pub fn deinit(self: *Elf) void { self.rela_dyn.deinit(gpa); self.rela_plt.deinit(gpa); self.zig_got.deinit(gpa); + self.comdat_group_sections.deinit(gpa); } pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 { @@ -3585,10 +3589,35 @@ fn initSectionsObject(self: *Elf) !void { self.eh_frame_rela_section_index = try self.addRelaShdr(".rela.eh_frame", self.eh_frame_section_index.?); } + try self.initComdatGroups(); try self.initSymtab(); try self.initShStrtab(); } +fn initComdatGroups(self: *Elf) !void { + const gpa = self.base.allocator; + + for (self.objects.items) |index| { + const object = self.file(index).?.object; + + for (object.comdat_groups.items) |cg_index| { + const cg = self.comdatGroup(cg_index); + const cg_owner = self.comdatGroupOwner(cg.owner); + if (cg_owner.file != index) continue; + + const cg_sec = try self.comdat_group_sections.addOne(gpa); + cg_sec.* = .{ + .shndx = try self.addSection(.{ + .name = ".group", + .type = elf.SHT_GROUP, + .entsize = @sizeOf(u32), + }), + .cg_index = cg_index, + }; + } + } +} + fn initSymtab(self: *Elf) !void { const small_ptr = switch (self.ptr_width) { .p32 => true, @@ -3892,7 +3921,7 @@ fn shdrRank(self: *Elf, shndx: u16) u8 { elf.SHT_DYNAMIC => return 0xf3, - elf.SHT_RELA => return 0xf, + elf.SHT_RELA, elf.SHT_GROUP => return 0xf, elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) { if (flags & elf.SHF_EXECINSTR != 0) { @@ -4131,6 +4160,10 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u16) !void { shdr.sh_link = self.symtab_section_index.?; shdr.sh_info = shndx; } + + for (self.comdat_group_sections.items) |*cg| { + cg.shndx = backlinks[cg.shndx]; + } } fn updateSectionSizes(self: *Elf) !void { @@ -4260,10 +4293,15 @@ fn updateSectionSizesObject(self: *Elf) !void { shdr.sh_size = eh_frame.calcEhFrameRelocs(self) * shdr.sh_entsize; } + self.updateComdatGroupsSizes(); try self.updateSymtabSize(); self.updateShStrtabSize(); } +fn updateComdatGroupsSizes(self: *Elf) void { + _ = self; +} + fn updateShStrtabSize(self: *Elf) void { if (self.shstrtab_section_index) |index| { self.shdrs.items[index].sh_size = self.shstrtab.items.len; @@ -6168,7 +6206,12 @@ fn fmtDumpState( try writer.print("{}\n", .{self.got.fmt(self)}); try writer.print("{}\n", .{self.zig_got.fmt(self)}); - try writer.writeAll("Output shdrs\n"); + try writer.writeAll("Output COMDAT groups\n"); + for (self.comdat_group_sections.items) |cg| { + try writer.print("shdr({d}) : COMDAT({d})\n", .{ cg.shndx, cg.cg_index }); + } + + try writer.writeAll("\nOutput shdrs\n"); for (self.shdrs.items, 0..) |shdr, shndx| { try writer.print("shdr({d}) : phdr({?d}) : {}\n", .{ shndx, @@ -6332,6 +6375,7 @@ const Archive = @import("Elf/Archive.zig"); pub const Atom = @import("Elf/Atom.zig"); const Cache = std.Build.Cache; const Compilation = @import("../Compilation.zig"); +const ComdatGroupSection = synthetic_sections.ComdatGroupSection; const CopyRelSection = synthetic_sections.CopyRelSection; const DynamicSection = synthetic_sections.DynamicSection; const DynsymSection = synthetic_sections.DynsymSection; diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index ce9b83c9bb..7b4add7f53 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -142,7 +142,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32)); const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers]; - if (group_members[0] != 0x1) { // GRP_COMDAT + if (group_members[0] != elf.GRP_COMDAT) { // TODO convert into an error log.debug("{}: unknown SHT_GROUP format", .{self.fmtPath()}); continue; @@ -939,16 +939,17 @@ fn formatComdatGroups( _ = options; const object = ctx.object; const elf_file = ctx.elf_file; - try writer.writeAll(" comdat groups\n"); + try writer.writeAll(" COMDAT groups\n"); for (object.comdat_groups.items) |cg_index| { const cg = elf_file.comdatGroup(cg_index); const cg_owner = elf_file.comdatGroupOwner(cg.owner); if (cg_owner.file != object.index) continue; + try writer.print(" COMDAT({d})\n", .{cg_index}); const cg_members = object.comdatGroupMembers(cg.shndx); for (cg_members) |shndx| { const atom_index = object.atoms.items[shndx]; const atom = elf_file.atom(atom_index) orelse continue; - try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom.name(elf_file) }); + try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom.name(elf_file) }); } } } diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 0c9f94b5b9..7fbc75d80a 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -1499,6 +1499,30 @@ pub const VerneedSection = struct { } }; +pub const ComdatGroupSection = struct { + shndx: u32, + cg_index: u32, + + // pub fn size(cg: ComdatGroupSection) usize { + // return cg.members.items.len + 1; + // } + + // pub fn write(cg: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void { + // try writeInt(@as(u32, elf.GRP_COMDAT), elf_file, writer); + // for (cg.members.items) |atom_index| { + // const atom = elf_file.atom(atom_index); + // const input_shdr = atom.inputShdr(elf_file); + // switch (input_shdr.sh_type) { + // elf.SHT_RELA => { + + // }, + // else => {}, + // } + // } + // try writer.writeAll(mem.sliceAsBytes(cg.members.items)); + // } +}; + fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void { const entry_size = elf_file.archPtrWidthBytes(); const endian = elf_file.base.options.target.cpu.arch.endian();