authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-06-06 16:25:17-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-06-06 16:25:17-04:00
log98646e5cf8a59e5a7d47eaf863d57ad26313c61c
tree2798cabc394f95dfd1b4ae569b3bbb0baaf3cec8
parentb6d904624296dc5c60c34d8613d6c261e60328cf
parentbcf387f0b9e3911ade500313dc1624b67a011619
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #24094 from jacobly0/x86_64-ld-scripts

link: support static archives that are linker scripts

6 files changed, 103 insertions(+), 102 deletions(-)

src/link.zig+11-11
......@@ -2294,9 +2294,10 @@ fn resolvePathInputLib(
22942294 const test_path: Path = pq.path;
22952295 // In the case of shared libraries, they might actually be "linker scripts"
22962296 // that contain references to other libraries.
2297 if (pq.query.allow_so_scripts and target.ofmt == .elf and
2298 Compilation.classifyFileExt(test_path.sub_path) == .shared_library)
2299 {
2297 if (pq.query.allow_so_scripts and target.ofmt == .elf and switch (Compilation.classifyFileExt(test_path.sub_path)) {
2298 .static_library, .shared_library => true,
2299 else => false,
2300 }) {
23002301 var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
23012302 error.FileNotFound => return .no_match,
23022303 else => |e| fatal("unable to search for {s} library '{'}': {s}", .{
......@@ -2304,14 +2305,13 @@ fn resolvePathInputLib(
23042305 }),
23052306 };
23062307 errdefer file.close();
2307 try ld_script_bytes.resize(gpa, @sizeOf(std.elf.Elf64_Ehdr));
2308 try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len));
23082309 const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{'}': {s}", .{
23092310 test_path, @errorName(err),
23102311 });
2311 elf_file: {
2312 if (n != ld_script_bytes.items.len) break :elf_file;
2313 if (!mem.eql(u8, ld_script_bytes.items[0..4], "\x7fELF")) break :elf_file;
2314 // Appears to be an ELF file.
2312 const buf = ld_script_bytes.items[0..n];
2313 if (mem.startsWith(u8, buf, std.elf.MAGIC) or mem.startsWith(u8, buf, std.elf.ARMAG)) {
2314 // Appears to be an ELF or archive file.
23152315 return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, pq.query);
23162316 }
23172317 const stat = file.stat() catch |err|
......@@ -2319,10 +2319,10 @@ fn resolvePathInputLib(
23192319 const size = std.math.cast(u32, stat.size) orelse
23202320 fatal("{}: linker script too big", .{test_path});
23212321 try ld_script_bytes.resize(gpa, size);
2322 const buf = ld_script_bytes.items[n..];
2323 const n2 = file.preadAll(buf, n) catch |err|
2322 const buf2 = ld_script_bytes.items[n..];
2323 const n2 = file.preadAll(buf2, n) catch |err|
23242324 fatal("failed to read {}: {s}", .{ test_path, @errorName(err) });
2325 if (n2 != buf.len) fatal("failed to read {}: unexpected end of file", .{test_path});
2325 if (n2 != buf2.len) fatal("failed to read {}: unexpected end of file", .{test_path});
23262326 var diags = Diags.init(gpa);
23272327 defer diags.deinit();
23282328 const ld_script_result = LdScript.parse(gpa, &diags, test_path, ld_script_bytes.items);
src/link/Elf.zig+20-19
......@@ -99,7 +99,7 @@ copy_rel: CopyRelSection = .{},
9999rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .empty,
100100/// SHT_GROUP sections
101101/// Applies only to a relocatable.
102comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .empty,
102group_sections: std.ArrayListUnmanaged(GroupSection) = .empty,
103103
104104resolver: SymbolResolver = .{},
105105
......@@ -510,7 +510,7 @@ pub fn deinit(self: *Elf) void {
510510 self.copy_rel.deinit(gpa);
511511 self.rela_dyn.deinit(gpa);
512512 self.rela_plt.deinit(gpa);
513 self.comdat_group_sections.deinit(gpa);
513 self.group_sections.deinit(gpa);
514514 self.dump_argv_list.deinit(gpa);
515515}
516516
......@@ -919,7 +919,7 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
919919 &self.sections,
920920 self.shstrtab.items,
921921 self.merge_sections.items,
922 self.comdat_group_sections.items,
922 self.group_sections.items,
923923 self.zigObjectPtr(),
924924 self.files,
925925 );
......@@ -1315,16 +1315,16 @@ pub fn resolveSymbols(self: *Elf) !void {
13151315 }
13161316
13171317 {
1318 // Dedup comdat groups.
1318 // Dedup groups.
13191319 var table = std.StringHashMap(Ref).init(self.base.comp.gpa);
13201320 defer table.deinit();
13211321
13221322 for (self.objects.items) |index| {
1323 try self.file(index).?.object.resolveComdatGroups(self, &table);
1323 try self.file(index).?.object.resolveGroups(self, &table);
13241324 }
13251325
13261326 for (self.objects.items) |index| {
1327 self.file(index).?.object.markComdatGroupsDead(self);
1327 self.file(index).?.object.markGroupsDead(self);
13281328 }
13291329 }
13301330
......@@ -3125,7 +3125,7 @@ pub fn sortShdrs(
31253125 sections: *std.MultiArrayList(Section),
31263126 shstrtab: []const u8,
31273127 merge_sections: []Merge.Section,
3128 comdat_group_sections: []ComdatGroupSection,
3128 comdat_group_sections: []GroupSection,
31293129 zig_object_ptr: ?*ZigObject,
31303130 files: std.MultiArrayList(File.Entry),
31313131) !void {
......@@ -4446,8 +4446,8 @@ pub fn atom(self: *Elf, ref: Ref) ?*Atom {
44464446 return file_ptr.atom(ref.index);
44474447}
44484448
4449pub fn comdatGroup(self: *Elf, ref: Ref) *ComdatGroup {
4450 return self.file(ref.file).?.comdatGroup(ref.index);
4449pub fn group(self: *Elf, ref: Ref) *Group {
4450 return self.file(ref.file).?.group(ref.index);
44514451}
44524452
44534453pub fn symbol(self: *Elf, ref: Ref) ?*Symbol {
......@@ -4814,7 +4814,7 @@ fn fmtDumpState(
48144814 object.fmtCies(self),
48154815 object.fmtFdes(self),
48164816 object.fmtSymtab(self),
4817 object.fmtComdatGroups(self),
4817 object.fmtGroups(self),
48184818 });
48194819 }
48204820
......@@ -4852,9 +4852,9 @@ fn fmtDumpState(
48524852 try writer.print("{}\n", .{self.got.fmt(self)});
48534853 try writer.print("{}\n", .{self.plt.fmt(self)});
48544854
4855 try writer.writeAll("Output COMDAT groups\n");
4856 for (self.comdat_group_sections.items) |cg| {
4857 try writer.print(" shdr({d}) : COMDAT({})\n", .{ cg.shndx, cg.cg_ref });
4855 try writer.writeAll("Output groups\n");
4856 for (self.group_sections.items) |cg| {
4857 try writer.print(" shdr({d}) : GROUP({})\n", .{ cg.shndx, cg.cg_ref });
48584858 }
48594859
48604860 try writer.writeAll("\nOutput merge sections\n");
......@@ -4934,25 +4934,26 @@ const default_entry_addr = 0x8000000;
49344934
49354935pub const base_tag: link.File.Tag = .elf;
49364936
4937pub const ComdatGroup = struct {
4937pub const Group = struct {
49384938 signature_off: u32,
49394939 file_index: File.Index,
49404940 shndx: u32,
49414941 members_start: u32,
49424942 members_len: u32,
4943 is_comdat: bool,
49434944 alive: bool = true,
49444945
4945 pub fn file(cg: ComdatGroup, elf_file: *Elf) File {
4946 pub fn file(cg: Group, elf_file: *Elf) File {
49464947 return elf_file.file(cg.file_index).?;
49474948 }
49484949
4949 pub fn signature(cg: ComdatGroup, elf_file: *Elf) [:0]const u8 {
4950 pub fn signature(cg: Group, elf_file: *Elf) [:0]const u8 {
49504951 return cg.file(elf_file).object.getString(cg.signature_off);
49514952 }
49524953
4953 pub fn comdatGroupMembers(cg: ComdatGroup, elf_file: *Elf) []const u32 {
4954 pub fn members(cg: Group, elf_file: *Elf) []const u32 {
49544955 const object = cg.file(elf_file).object;
4955 return object.comdat_group_data.items[cg.members_start..][0..cg.members_len];
4956 return object.group_data.items[cg.members_start..][0..cg.members_len];
49564957 }
49574958
49584959 pub const Index = u32;
......@@ -5310,7 +5311,7 @@ const Air = @import("../Air.zig");
53105311const Archive = @import("Elf/Archive.zig");
53115312const AtomList = @import("Elf/AtomList.zig");
53125313const Compilation = @import("../Compilation.zig");
5313const ComdatGroupSection = synthetic_sections.ComdatGroupSection;
5314const GroupSection = synthetic_sections.GroupSection;
53145315const CopyRelSection = synthetic_sections.CopyRelSection;
53155316const Diags = @import("../link.zig").Diags;
53165317const DynamicSection = synthetic_sections.DynamicSection;
src/link/Elf/Object.zig+45-45
......@@ -20,8 +20,8 @@ atoms: std.ArrayListUnmanaged(Atom) = .empty,
2020atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .empty,
2121atoms_extra: std.ArrayListUnmanaged(u32) = .empty,
2222
23comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup) = .empty,
24comdat_group_data: std.ArrayListUnmanaged(u32) = .empty,
23groups: std.ArrayListUnmanaged(Elf.Group) = .empty,
24group_data: std.ArrayListUnmanaged(u32) = .empty,
2525
2626input_merge_sections: std.ArrayListUnmanaged(Merge.InputSection) = .empty,
2727input_merge_sections_indexes: std.ArrayListUnmanaged(Merge.InputSection.Index) = .empty,
......@@ -49,8 +49,8 @@ pub fn deinit(self: *Object, gpa: Allocator) void {
4949 self.atoms.deinit(gpa);
5050 self.atoms_indexes.deinit(gpa);
5151 self.atoms_extra.deinit(gpa);
52 self.comdat_groups.deinit(gpa);
53 self.comdat_group_data.deinit(gpa);
52 self.groups.deinit(gpa);
53 self.group_data.deinit(gpa);
5454 self.relocs.deinit(gpa);
5555 self.fdes.deinit(gpa);
5656 self.cies.deinit(gpa);
......@@ -304,22 +304,22 @@ fn initAtoms(
304304 }
305305 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
306306
307 if (group_members[0] != elf.GRP_COMDAT) {
308 return diags.failParse(path, "corrupt section group: unknown SHT_GROUP format", .{});
307 switch (group_members[0]) {
308 0, elf.GRP_COMDAT => {
309 const group_start: u32 = @intCast(self.group_data.items.len);
310 try self.group_data.appendUnalignedSlice(gpa, group_members[1..]);
311
312 self.group(try self.addGroup(gpa)).* = .{
313 .signature_off = group_signature,
314 .file_index = self.index,
315 .shndx = shndx,
316 .members_start = group_start,
317 .members_len = @intCast(group_nmembers - 1),
318 .is_comdat = group_members[0] == elf.GRP_COMDAT,
319 };
320 },
321 else => return diags.failParse(path, "corrupt section group: unknown SHT_GROUP format", .{}),
309322 }
310
311 const group_start: u32 = @intCast(self.comdat_group_data.items.len);
312 try self.comdat_group_data.appendUnalignedSlice(gpa, group_members[1..]);
313
314 const comdat_group_index = try self.addComdatGroup(gpa);
315 const comdat_group = self.comdatGroup(comdat_group_index);
316 comdat_group.* = .{
317 .signature_off = group_signature,
318 .file_index = self.index,
319 .shndx = shndx,
320 .members_start = group_start,
321 .members_len = @intCast(group_nmembers - 1),
322 };
323323 },
324324
325325 elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"),
......@@ -986,28 +986,28 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
986986 }
987987}
988988
989pub fn resolveComdatGroups(self: *Object, elf_file: *Elf, table: anytype) !void {
990 for (self.comdat_groups.items, 0..) |*cg, cgi| {
991 const signature = cg.signature(elf_file);
989pub fn resolveGroups(self: *Object, elf_file: *Elf, table: anytype) !void {
990 for (self.groups.items, 0..) |*g, gi| {
991 const signature = g.signature(elf_file);
992992 const gop = try table.getOrPut(signature);
993993 if (!gop.found_existing) {
994 gop.value_ptr.* = .{ .index = @intCast(cgi), .file = self.index };
994 gop.value_ptr.* = .{ .index = @intCast(gi), .file = self.index };
995995 continue;
996996 }
997 const current = elf_file.comdatGroup(gop.value_ptr.*);
998 cg.alive = false;
997 const current = elf_file.group(gop.value_ptr.*);
998 g.alive = false;
999999 if (self.index < current.file_index) {
10001000 current.alive = false;
1001 cg.alive = true;
1002 gop.value_ptr.* = .{ .index = @intCast(cgi), .file = self.index };
1001 g.alive = true;
1002 gop.value_ptr.* = .{ .index = @intCast(gi), .file = self.index };
10031003 }
10041004 }
10051005}
10061006
1007pub fn markComdatGroupsDead(self: *Object, elf_file: *Elf) void {
1008 for (self.comdat_groups.items) |cg| {
1009 if (cg.alive) continue;
1010 for (cg.comdatGroupMembers(elf_file)) |shndx| {
1007pub fn markGroupsDead(self: *Object, elf_file: *Elf) void {
1008 for (self.groups.items) |g| {
1009 if (g.alive) continue;
1010 for (g.members(elf_file)) |shndx| {
10111011 const atom_index = self.atoms_indexes.items[shndx];
10121012 if (self.atom(atom_index)) |atom_ptr| {
10131013 atom_ptr.alive = false;
......@@ -1421,15 +1421,15 @@ fn inputMergeSection(self: *Object, index: Merge.InputSection.Index) ?*Merge.Inp
14211421 return &self.input_merge_sections.items[index];
14221422}
14231423
1424fn addComdatGroup(self: *Object, gpa: Allocator) !Elf.ComdatGroup.Index {
1425 const index = @as(Elf.ComdatGroup.Index, @intCast(self.comdat_groups.items.len));
1426 _ = try self.comdat_groups.addOne(gpa);
1424fn addGroup(self: *Object, gpa: Allocator) !Elf.Group.Index {
1425 const index: Elf.Group.Index = @intCast(self.groups.items.len);
1426 _ = try self.groups.addOne(gpa);
14271427 return index;
14281428}
14291429
1430pub fn comdatGroup(self: *Object, index: Elf.ComdatGroup.Index) *Elf.ComdatGroup {
1431 assert(index < self.comdat_groups.items.len);
1432 return &self.comdat_groups.items[index];
1430pub fn group(self: *Object, index: Elf.Group.Index) *Elf.Group {
1431 assert(index < self.groups.items.len);
1432 return &self.groups.items[index];
14331433}
14341434
14351435pub fn format(
......@@ -1550,14 +1550,14 @@ fn formatFdes(
15501550 }
15511551}
15521552
1553pub fn fmtComdatGroups(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatComdatGroups) {
1553pub fn fmtGroups(self: *Object, elf_file: *Elf) std.fmt.Formatter(formatGroups) {
15541554 return .{ .data = .{
15551555 .object = self,
15561556 .elf_file = elf_file,
15571557 } };
15581558}
15591559
1560fn formatComdatGroups(
1560fn formatGroups(
15611561 ctx: FormatContext,
15621562 comptime unused_fmt_string: []const u8,
15631563 options: std.fmt.FormatOptions,
......@@ -1567,13 +1567,13 @@ fn formatComdatGroups(
15671567 _ = options;
15681568 const object = ctx.object;
15691569 const elf_file = ctx.elf_file;
1570 try writer.writeAll(" COMDAT groups\n");
1571 for (object.comdat_groups.items, 0..) |cg, cg_index| {
1572 try writer.print(" COMDAT({d})", .{cg_index});
1573 if (!cg.alive) try writer.writeAll(" : [*]");
1570 try writer.writeAll(" groups\n");
1571 for (object.groups.items, 0..) |g, g_index| {
1572 try writer.print(" {s}({d})", .{ if (g.is_comdat) "COMDAT" else "GROUP", g_index });
1573 if (!g.alive) try writer.writeAll(" : [*]");
15741574 try writer.writeByte('\n');
1575 const cg_members = cg.comdatGroupMembers(elf_file);
1576 for (cg_members) |shndx| {
1575 const g_members = g.members(elf_file);
1576 for (g_members) |shndx| {
15771577 const atom_index = object.atoms_indexes.items[shndx];
15781578 const atom_ptr = object.atom(atom_index) orelse continue;
15791579 try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom_ptr.name(elf_file) });
src/link/Elf/file.zig+2-2
......@@ -198,10 +198,10 @@ pub const File = union(enum) {
198198 };
199199 }
200200
201 pub fn comdatGroup(file: File, ind: Elf.ComdatGroup.Index) *Elf.ComdatGroup {
201 pub fn group(file: File, ind: Elf.Group.Index) *Elf.Group {
202202 return switch (file) {
203203 .linker_defined, .shared_object, .zig_object => unreachable,
204 .object => |x| x.comdatGroup(ind),
204 .object => |x| x.group(ind),
205205 };
206206 }
207207
src/link/Elf/relocatable.zig+13-13
......@@ -19,7 +19,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
1919 &elf_file.sections,
2020 elf_file.shstrtab.items,
2121 elf_file.merge_sections.items,
22 elf_file.comdat_group_sections.items,
22 elf_file.group_sections.items,
2323 elf_file.zigObjectPtr(),
2424 elf_file.files,
2525 );
......@@ -152,7 +152,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void {
152152 &elf_file.sections,
153153 elf_file.shstrtab.items,
154154 elf_file.merge_sections.items,
155 elf_file.comdat_group_sections.items,
155 elf_file.group_sections.items,
156156 elf_file.zigObjectPtr(),
157157 elf_file.files,
158158 );
......@@ -233,19 +233,19 @@ fn initSections(elf_file: *Elf) !void {
233233 );
234234 }
235235
236 try initComdatGroups(elf_file);
236 try initGroups(elf_file);
237237 try elf_file.initSymtab();
238238 try elf_file.initShStrtab();
239239}
240240
241fn initComdatGroups(elf_file: *Elf) !void {
241fn initGroups(elf_file: *Elf) !void {
242242 const gpa = elf_file.base.comp.gpa;
243243
244244 for (elf_file.objects.items) |index| {
245245 const object = elf_file.file(index).?.object;
246 for (object.comdat_groups.items, 0..) |cg, cg_index| {
246 for (object.groups.items, 0..) |cg, cg_index| {
247247 if (!cg.alive) continue;
248 const cg_sec = try elf_file.comdat_group_sections.addOne(gpa);
248 const cg_sec = try elf_file.group_sections.addOne(gpa);
249249 cg_sec.* = .{
250250 .shndx = try elf_file.addSection(.{
251251 .name = try elf_file.insertShString(".group"),
......@@ -292,12 +292,12 @@ fn updateSectionSizes(elf_file: *Elf) !void {
292292 }
293293
294294 try elf_file.updateSymtabSize();
295 updateComdatGroupsSizes(elf_file);
295 updateGroupsSizes(elf_file);
296296 elf_file.updateShStrtabSize();
297297}
298298
299fn updateComdatGroupsSizes(elf_file: *Elf) void {
300 for (elf_file.comdat_group_sections.items) |cg| {
299fn updateGroupsSizes(elf_file: *Elf) void {
300 for (elf_file.group_sections.items) |cg| {
301301 const shdr = &elf_file.sections.items(.shdr)[cg.shndx];
302302 shdr.sh_size = cg.size(elf_file);
303303 shdr.sh_link = elf_file.section_indexes.symtab.?;
......@@ -436,21 +436,21 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
436436 try elf_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset);
437437 }
438438
439 try writeComdatGroups(elf_file);
439 try writeGroups(elf_file);
440440 try elf_file.writeSymtab();
441441 try elf_file.writeShStrtab();
442442}
443443
444fn writeComdatGroups(elf_file: *Elf) !void {
444fn writeGroups(elf_file: *Elf) !void {
445445 const gpa = elf_file.base.comp.gpa;
446 for (elf_file.comdat_group_sections.items) |cgs| {
446 for (elf_file.group_sections.items) |cgs| {
447447 const shdr = elf_file.sections.items(.shdr)[cgs.shndx];
448448 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
449449 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
450450 defer buffer.deinit();
451451 try cgs.write(elf_file, buffer.writer());
452452 assert(buffer.items.len == sh_size);
453 log.debug("writing COMDAT group from 0x{x} to 0x{x}", .{
453 log.debug("writing group from 0x{x} to 0x{x}", .{
454454 shdr.sh_offset,
455455 shdr.sh_offset + shdr.sh_size,
456456 });
src/link/Elf/synthetic_sections.zig+12-12
......@@ -1484,33 +1484,33 @@ pub const VerneedSection = struct {
14841484 }
14851485};
14861486
1487pub const ComdatGroupSection = struct {
1487pub const GroupSection = struct {
14881488 shndx: u32,
14891489 cg_ref: Elf.Ref,
14901490
1491 fn comdatGroup(cgs: ComdatGroupSection, elf_file: *Elf) *Elf.ComdatGroup {
1491 fn group(cgs: GroupSection, elf_file: *Elf) *Elf.Group {
14921492 const cg_file = elf_file.file(cgs.cg_ref.file).?;
1493 return cg_file.object.comdatGroup(cgs.cg_ref.index);
1493 return cg_file.object.group(cgs.cg_ref.index);
14941494 }
14951495
1496 pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) *Symbol {
1497 const cg = cgs.comdatGroup(elf_file);
1496 pub fn symbol(cgs: GroupSection, elf_file: *Elf) *Symbol {
1497 const cg = cgs.group(elf_file);
14981498 const object = cg.file(elf_file).object;
14991499 const shdr = object.shdrs.items[cg.shndx];
15001500 return &object.symbols.items[shdr.sh_info];
15011501 }
15021502
1503 pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize {
1504 const cg = cgs.comdatGroup(elf_file);
1505 const members = cg.comdatGroupMembers(elf_file);
1503 pub fn size(cgs: GroupSection, elf_file: *Elf) usize {
1504 const cg = cgs.group(elf_file);
1505 const members = cg.members(elf_file);
15061506 return (members.len + 1) * @sizeOf(u32);
15071507 }
15081508
1509 pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void {
1510 const cg = cgs.comdatGroup(elf_file);
1509 pub fn write(cgs: GroupSection, elf_file: *Elf, writer: anytype) !void {
1510 const cg = cgs.group(elf_file);
15111511 const object = cg.file(elf_file).object;
1512 const members = cg.comdatGroupMembers(elf_file);
1513 try writer.writeInt(u32, elf.GRP_COMDAT, .little);
1512 const members = cg.members(elf_file);
1513 try writer.writeInt(u32, if (cg.is_comdat) elf.GRP_COMDAT else 0, .little);
15141514 for (members) |shndx| {
15151515 const shdr = object.shdrs.items[shndx];
15161516 switch (shdr.sh_type) {