Commit acd7cbf0b5

Jakub Konka <kubkon@jakubkonka.com>
2023-11-09 17:41:14
elf: init output COMDAT group sections
1 parent 031d9fa
Changed files (4)
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;
 
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) });
         }
     }
 }
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();
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;