authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-25 16:47:43+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-30 10:00:50+02:00
logc575e3daa4cdb39e38cc0b32fc8fe4a917947d34
treed0e01d739543c5783d57e046e301c9179ea5692c
parentfa09276510b03292ace9b8cc72064341530a1940

elf: resolve COMDATs in more parallel-friendly way


7 files changed, 138 insertions(+), 125 deletions(-)

src/link/Elf.zig+27-92
...@@ -215,11 +215,8 @@ merge_subsections: std.ArrayListUnmanaged(MergeSubsection) = .{},...@@ -215,11 +215,8 @@ merge_subsections: std.ArrayListUnmanaged(MergeSubsection) = .{},
215/// Table of last atom index in a section and matching atom free list if any.215/// Table of last atom index in a section and matching atom free list if any.
216last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},216last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
217217
218comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
219comdat_groups_table: std.ArrayHashMapUnmanaged(ComdatGroupKey, ComdatGroupOwner.Index, ComdatGroupContext, false) = .{},
220
221/// Global string table used to provide quick access to global symbol resolvers218/// Global string table used to provide quick access to global symbol resolvers
222/// such as `resolver` and `comdat_groups_table`.219/// such as `resolver`.
223strings: StringTable = .{},220strings: StringTable = .{},
224221
225first_eflags: ?elf.Elf64_Word = null,222first_eflags: ?elf.Elf64_Word = null,
...@@ -506,8 +503,6 @@ pub fn deinit(self: *Elf) void {...@@ -506,8 +503,6 @@ pub fn deinit(self: *Elf) void {
506 }503 }
507 self.last_atom_and_free_list_table.deinit(gpa);504 self.last_atom_and_free_list_table.deinit(gpa);
508505
509 self.comdat_groups_owners.deinit(gpa);
510 self.comdat_groups_table.deinit(gpa);
511 self.strings.deinit(gpa);506 self.strings.deinit(gpa);
512507
513 self.got.deinit(gpa);508 self.got.deinit(gpa);
...@@ -1305,7 +1300,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -1305,7 +1300,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1305 // input Object files.1300 // input Object files.
1306 // Any qualifing unresolved symbol will be upgraded to an absolute, weak1301 // Any qualifing unresolved symbol will be upgraded to an absolute, weak
1307 // symbol for potential resolution at load-time.1302 // symbol for potential resolution at load-time.
1308 self.resolveSymbols();1303 try self.resolveSymbols();
1309 self.markEhFrameAtomsDead();1304 self.markEhFrameAtomsDead();
1310 try self.resolveMergeSections();1305 try self.resolveMergeSections();
13111306
...@@ -1955,7 +1950,7 @@ fn accessLibPath(...@@ -1955,7 +1950,7 @@ fn accessLibPath(
1955/// 4. Reset state of all resolved globals since we will redo this bit on the pruned set.1950/// 4. Reset state of all resolved globals since we will redo this bit on the pruned set.
1956/// 5. Remove references to dead objects/shared objects1951/// 5. Remove references to dead objects/shared objects
1957/// 6. Re-run symbol resolution on pruned objects and shared objects sets.1952/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1958pub fn resolveSymbols(self: *Elf) void {1953pub fn resolveSymbols(self: *Elf) !void {
1959 // Resolve symbols in the ZigObject. For now, we assume that it's always live.1954 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
1960 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);1955 if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
1961 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).1956 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
...@@ -1986,32 +1981,17 @@ pub fn resolveSymbols(self: *Elf) void {...@@ -1986,32 +1981,17 @@ pub fn resolveSymbols(self: *Elf) void {
1986 } else i += 1;1981 } else i += 1;
1987 }1982 }
19881983
1989 // Dedup comdat groups.1984 {
1990 for (self.objects.items) |index| {1985 // Dedup comdat groups.
1991 const object = self.file(index).?.object;1986 var table = std.StringHashMap(Ref).init(self.base.comp.gpa);
1992 for (object.comdat_groups.items) |cg| {1987 defer table.deinit();
1993 const cg_owner = self.comdatGroupOwner(cg.owner);1988
1994 const owner_file_index = if (self.file(cg_owner.file)) |file_ptr|1989 for (self.objects.items) |index| {
1995 file_ptr.object.index1990 try self.file(index).?.object.resolveComdatGroups(self, &table);
1996 else
1997 std.math.maxInt(File.Index);
1998 cg_owner.file = @min(owner_file_index, index);
1999 }1991 }
2000 }
20011992
2002 for (self.objects.items) |index| {1993 for (self.objects.items) |index| {
2003 const object = self.file(index).?.object;1994 self.file(index).?.object.markComdatGroupsDead(self);
2004 for (object.comdat_groups.items) |cg| {
2005 const cg_owner = self.comdatGroupOwner(cg.owner);
2006 if (cg_owner.file != index) {
2007 for (cg.comdatGroupMembers(self)) |shndx| {
2008 const atom_index = object.atoms_indexes.items[shndx];
2009 if (object.atom(atom_index)) |atom_ptr| {
2010 atom_ptr.flags.alive = false;
2011 atom_ptr.markFdesDead(self);
2012 }
2013 }
2014 }
2015 }1995 }
2016 }1996 }
20171997
...@@ -5632,6 +5612,10 @@ pub fn atom(self: *Elf, ref: Ref) ?*Atom {...@@ -5632,6 +5612,10 @@ pub fn atom(self: *Elf, ref: Ref) ?*Atom {
5632 return file_ptr.atom(ref.index);5612 return file_ptr.atom(ref.index);
5633}5613}
56345614
5615pub fn comdatGroup(self: *Elf, ref: Ref) *ComdatGroup {
5616 return self.file(ref.file).?.comdatGroup(ref.index);
5617}
5618
5635/// Returns pointer-to-symbol described at sym_index.5619/// Returns pointer-to-symbol described at sym_index.
5636pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {5620pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {
5637 return &self.symbols.items[sym_index];5621 return &self.symbols.items[sym_index];
...@@ -5737,31 +5721,6 @@ pub fn zigObjectPtr(self: *Elf) ?*ZigObject {...@@ -5737,31 +5721,6 @@ pub fn zigObjectPtr(self: *Elf) ?*ZigObject {
5737 return self.file(index).?.zig_object;5721 return self.file(index).?.zig_object;
5738}5722}
57395723
5740const GetOrCreateComdatGroupOwnerResult = struct {
5741 found_existing: bool,
5742 index: ComdatGroupOwner.Index,
5743};
5744
5745pub fn getOrCreateComdatGroupOwner(self: *Elf, key: ComdatGroupKey) !GetOrCreateComdatGroupOwnerResult {
5746 const gpa = self.base.comp.gpa;
5747 const gop = try self.comdat_groups_table.getOrPutContext(gpa, key, .{ .elf_file = self });
5748 if (!gop.found_existing) {
5749 const index: ComdatGroupOwner.Index = @intCast(self.comdat_groups_owners.items.len);
5750 const owner = try self.comdat_groups_owners.addOne(gpa);
5751 owner.* = .{};
5752 gop.value_ptr.* = index;
5753 }
5754 return .{
5755 .found_existing = gop.found_existing,
5756 .index = gop.value_ptr.*,
5757 };
5758}
5759
5760pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupOwner {
5761 assert(index < self.comdat_groups_owners.items.len);
5762 return &self.comdat_groups_owners.items[index];
5763}
5764
5765pub fn addMergeSubsection(self: *Elf) !MergeSubsection.Index {5724pub fn addMergeSubsection(self: *Elf) !MergeSubsection.Index {
5766 const index: MergeSubsection.Index = @intCast(self.merge_subsections.items.len);5725 const index: MergeSubsection.Index = @intCast(self.merge_subsections.items.len);
5767 const msec = try self.merge_subsections.addOne(self.base.comp.gpa);5726 const msec = try self.merge_subsections.addOne(self.base.comp.gpa);
...@@ -6243,48 +6202,24 @@ const default_entry_addr = 0x8000000;...@@ -6243,48 +6202,24 @@ const default_entry_addr = 0x8000000;
62436202
6244pub const base_tag: link.File.Tag = .elf;6203pub const base_tag: link.File.Tag = .elf;
62456204
6246const ComdatGroupKey = struct {6205pub const ComdatGroup = struct {
6247 /// String table offset.6206 signature_off: u32,
6248 off: u32,
6249
6250 /// File index.
6251 file_index: File.Index,6207 file_index: File.Index,
6208 shndx: u32,
6209 members_start: u32,
6210 members_len: u32,
6211 alive: bool = true,
62526212
6253 pub fn get(key: ComdatGroupKey, elf_file: *Elf) [:0]const u8 {6213 pub fn file(cg: ComdatGroup, elf_file: *Elf) File {
6254 const file_ptr = elf_file.file(key.file_index).?;6214 return elf_file.file(cg.file_index).?;
6255 return file_ptr.getString(key.off);
6256 }
6257};
6258
6259const ComdatGroupContext = struct {
6260 elf_file: *Elf,
6261
6262 pub fn eql(ctx: ComdatGroupContext, a: ComdatGroupKey, b: ComdatGroupKey, b_index: usize) bool {
6263 _ = b_index;
6264 const elf_file = ctx.elf_file;
6265 return mem.eql(u8, a.get(elf_file), b.get(elf_file));
6266 }6215 }
62676216
6268 pub fn hash(ctx: ComdatGroupContext, a: ComdatGroupKey) u32 {6217 pub fn signature(cg: ComdatGroup, elf_file: *Elf) [:0]const u8 {
6269 return std.array_hash_map.hashString(a.get(ctx.elf_file));6218 return cg.file(elf_file).object.getString(cg.signature_off);
6270 }6219 }
6271};
6272
6273const ComdatGroupOwner = struct {
6274 file: File.Index = 0,
6275
6276 const Index = u32;
6277};
6278
6279pub const ComdatGroup = struct {
6280 owner: ComdatGroupOwner.Index,
6281 file: File.Index,
6282 shndx: u32,
6283 members_start: u32,
6284 members_len: u32,
62856220
6286 pub fn comdatGroupMembers(cg: ComdatGroup, elf_file: *Elf) []const u32 {6221 pub fn comdatGroupMembers(cg: ComdatGroup, elf_file: *Elf) []const u32 {
6287 const object = elf_file.file(cg.file).?.object;6222 const object = cg.file(elf_file).object;
6288 return object.comdat_group_data.items[cg.members_start..][0..cg.members_len];6223 return object.comdat_group_data.items[cg.members_start..][0..cg.members_len];
6289 }6224 }
62906225
src/link/Elf/Atom.zig+4-1
...@@ -346,7 +346,10 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El...@@ -346,7 +346,10 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
346 r_sym = elf_file.sectionSymbolOutputSymtabIndex(msub.mergeSection(elf_file).output_section_index);346 r_sym = elf_file.sectionSymbolOutputSymtabIndex(msub.mergeSection(elf_file).output_section_index);
347 } else {347 } else {
348 r_addend += @intCast(target.address(.{}, elf_file));348 r_addend += @intCast(target.address(.{}, elf_file));
349 r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?);349 r_sym = if (target.outputShndx()) |osec|
350 elf_file.sectionSymbolOutputSymtabIndex(osec)
351 else
352 0;
350 },353 },
351 else => {354 else => {
352 r_sym = target.outputSymtabIndex(elf_file) orelse 0;355 r_sym = target.outputSymtabIndex(elf_file) orelse 0;
src/link/Elf/Object.zig+58-13
...@@ -216,27 +216,41 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:...@@ -216,27 +216,41 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
216 const shndx = @as(u32, @intCast(i));216 const shndx = @as(u32, @intCast(i));
217 const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);217 const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
218 defer allocator.free(group_raw_data);218 defer allocator.free(group_raw_data);
219 const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));219 const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch {
220 try elf_file.reportParseError2(
221 self.index,
222 "corrupt section group: not evenly divisible ",
223 .{},
224 );
225 return error.MalformedObject;
226 };
227 if (group_nmembers == 0) {
228 try elf_file.reportParseError2(
229 self.index,
230 "corrupt section group: empty section",
231 .{},
232 );
233 return error.MalformedObject;
234 }
220 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];235 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
221236
222 if (group_members[0] != elf.GRP_COMDAT) {237 if (group_members[0] != elf.GRP_COMDAT) {
223 // TODO convert into an error238 try elf_file.reportParseError2(
224 log.debug("{}: unknown SHT_GROUP format", .{self.fmtPath()});239 self.index,
225 continue;240 "corrupt section group: unknown SHT_GROUP format",
241 .{},
242 );
243 return error.MalformedObject;
226 }244 }
227245
228 const group_start = @as(u32, @intCast(self.comdat_group_data.items.len));246 const group_start = @as(u32, @intCast(self.comdat_group_data.items.len));
229 try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]);247 try self.comdat_group_data.appendUnalignedSlice(allocator, group_members[1..]);
230248
231 const gop = try elf_file.getOrCreateComdatGroupOwner(.{
232 .off = group_signature,
233 .file_index = self.index,
234 });
235 const comdat_group_index = try self.addComdatGroup(allocator);249 const comdat_group_index = try self.addComdatGroup(allocator);
236 const comdat_group = self.comdatGroup(comdat_group_index);250 const comdat_group = self.comdatGroup(comdat_group_index);
237 comdat_group.* = .{251 comdat_group.* = .{
238 .owner = gop.index,252 .signature_off = group_signature,
239 .file = self.index,253 .file_index = self.index,
240 .shndx = shndx,254 .shndx = shndx,
241 .members_start = group_start,255 .members_start = group_start,
242 .members_len = @intCast(group_nmembers - 1),256 .members_len = @intCast(group_nmembers - 1),
...@@ -912,6 +926,37 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {...@@ -912,6 +926,37 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
912 }926 }
913}927}
914928
929pub fn resolveComdatGroups(self: *Object, elf_file: *Elf, table: anytype) !void {
930 for (self.comdat_groups.items, 0..) |*cg, cgi| {
931 const signature = cg.signature(elf_file);
932 const gop = try table.getOrPut(signature);
933 if (!gop.found_existing) {
934 gop.value_ptr.* = .{ .index = @intCast(cgi), .file = self.index };
935 continue;
936 }
937 const current = elf_file.comdatGroup(gop.value_ptr.*);
938 cg.alive = false;
939 if (self.index < current.file_index) {
940 current.alive = false;
941 cg.alive = true;
942 gop.value_ptr.* = .{ .index = @intCast(cgi), .file = self.index };
943 }
944 }
945}
946
947pub fn markComdatGroupsDead(self: *Object, elf_file: *Elf) void {
948 for (self.comdat_groups.items) |cg| {
949 if (cg.alive) continue;
950 for (cg.comdatGroupMembers(elf_file)) |shndx| {
951 const atom_index = self.atoms_indexes.items[shndx];
952 if (self.atom(atom_index)) |atom_ptr| {
953 atom_ptr.flags.alive = false;
954 atom_ptr.markFdesDead(elf_file);
955 }
956 }
957 }
958}
959
915pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {960pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
916 for (self.atoms_indexes.items) |atom_index| {961 for (self.atoms_indexes.items) |atom_index| {
917 const atom_ptr = self.atom(atom_index) orelse continue;962 const atom_ptr = self.atom(atom_index) orelse continue;
...@@ -1428,9 +1473,9 @@ fn formatComdatGroups(...@@ -1428,9 +1473,9 @@ fn formatComdatGroups(
1428 const elf_file = ctx.elf_file;1473 const elf_file = ctx.elf_file;
1429 try writer.writeAll(" COMDAT groups\n");1474 try writer.writeAll(" COMDAT groups\n");
1430 for (object.comdat_groups.items, 0..) |cg, cg_index| {1475 for (object.comdat_groups.items, 0..) |cg, cg_index| {
1431 const cg_owner = elf_file.comdatGroupOwner(cg.owner);1476 try writer.print(" COMDAT({d})", .{cg_index});
1432 if (cg_owner.file != object.index) continue;1477 if (!cg.alive) try writer.writeAll(" : [*]");
1433 try writer.print(" COMDAT({d})\n", .{cg_index});1478 try writer.writeByte('\n');
1434 const cg_members = cg.comdatGroupMembers(elf_file);1479 const cg_members = cg.comdatGroupMembers(elf_file);
1435 for (cg_members) |shndx| {1480 for (cg_members) |shndx| {
1436 const atom_index = object.atoms_indexes.items[shndx];1481 const atom_index = object.atoms_indexes.items[shndx];
src/link/Elf/file.zig+7
...@@ -137,6 +137,13 @@ pub const File = union(enum) {...@@ -137,6 +137,13 @@ pub const File = union(enum) {
137 };137 };
138 }138 }
139139
140 pub fn comdatGroup(file: File, ind: Elf.ComdatGroup.Index) *Elf.ComdatGroup {
141 return switch (file) {
142 .linker_defined, .shared_object, .zig_object => unreachable,
143 .object => |x| x.comdatGroup(ind),
144 };
145 }
146
140 pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index {147 pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index {
141 return switch (file) {148 return switch (file) {
142 .zig_object => |x| x.symbol(ind),149 .zig_object => |x| x.symbol(ind),
src/link/Elf/relocatable.zig+2-5
...@@ -190,7 +190,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const...@@ -190,7 +190,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
190 // Now, we are ready to resolve the symbols across all input files.190 // Now, we are ready to resolve the symbols across all input files.
191 // We will first resolve the files in the ZigObject, next in the parsed191 // We will first resolve the files in the ZigObject, next in the parsed
192 // input Object files.192 // input Object files.
193 elf_file.resolveSymbols();193 try elf_file.resolveSymbols();
194 elf_file.markEhFrameAtomsDead();194 elf_file.markEhFrameAtomsDead();
195 try elf_file.resolveMergeSections();195 try elf_file.resolveMergeSections();
196 try elf_file.addCommentString();196 try elf_file.addCommentString();
...@@ -318,11 +318,8 @@ fn initComdatGroups(elf_file: *Elf) !void {...@@ -318,11 +318,8 @@ fn initComdatGroups(elf_file: *Elf) !void {
318318
319 for (elf_file.objects.items) |index| {319 for (elf_file.objects.items) |index| {
320 const object = elf_file.file(index).?.object;320 const object = elf_file.file(index).?.object;
321
322 for (object.comdat_groups.items, 0..) |cg, cg_index| {321 for (object.comdat_groups.items, 0..) |cg, cg_index| {
323 const cg_owner = elf_file.comdatGroupOwner(cg.owner);322 if (!cg.alive) continue;
324 if (cg_owner.file != index) continue;
325
326 const cg_sec = try elf_file.comdat_group_sections.addOne(gpa);323 const cg_sec = try elf_file.comdat_group_sections.addOne(gpa);
327 cg_sec.* = .{324 cg_sec.* = .{
328 .shndx = try elf_file.addSection(.{325 .shndx = try elf_file.addSection(.{
src/link/Elf/synthetic_sections.zig+2-8
...@@ -1672,12 +1672,6 @@ pub const ComdatGroupSection = struct {...@@ -1672,12 +1672,6 @@ pub const ComdatGroupSection = struct {
1672 shndx: u32,1672 shndx: u32,
1673 cg_ref: Elf.Ref,1673 cg_ref: Elf.Ref,
16741674
1675 fn ownerFile(cgs: ComdatGroupSection, elf_file: *Elf) ?File {
1676 const cg = cgs.comdatGroup(elf_file);
1677 const cg_owner = elf_file.comdatGroupOwner(cg.owner);
1678 return elf_file.file(cg_owner.file);
1679 }
1680
1681 fn comdatGroup(cgs: ComdatGroupSection, elf_file: *Elf) *Elf.ComdatGroup {1675 fn comdatGroup(cgs: ComdatGroupSection, elf_file: *Elf) *Elf.ComdatGroup {
1682 const cg_file = elf_file.file(cgs.cg_ref.file).?;1676 const cg_file = elf_file.file(cgs.cg_ref.file).?;
1683 return cg_file.object.comdatGroup(cgs.cg_ref.index);1677 return cg_file.object.comdatGroup(cgs.cg_ref.index);
...@@ -1685,7 +1679,7 @@ pub const ComdatGroupSection = struct {...@@ -1685,7 +1679,7 @@ pub const ComdatGroupSection = struct {
16851679
1686 pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index {1680 pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index {
1687 const cg = cgs.comdatGroup(elf_file);1681 const cg = cgs.comdatGroup(elf_file);
1688 const object = cgs.ownerFile(elf_file).?.object;1682 const object = cg.file(elf_file).object;
1689 const shdr = object.shdrs.items[cg.shndx];1683 const shdr = object.shdrs.items[cg.shndx];
1690 return object.symbols.items[shdr.sh_info];1684 return object.symbols.items[shdr.sh_info];
1691 }1685 }
...@@ -1698,7 +1692,7 @@ pub const ComdatGroupSection = struct {...@@ -1698,7 +1692,7 @@ pub const ComdatGroupSection = struct {
16981692
1699 pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void {1693 pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void {
1700 const cg = cgs.comdatGroup(elf_file);1694 const cg = cgs.comdatGroup(elf_file);
1701 const object = cgs.ownerFile(elf_file).?.object;1695 const object = cg.file(elf_file).object;
1702 const members = cg.comdatGroupMembers(elf_file);1696 const members = cg.comdatGroupMembers(elf_file);
1703 try writer.writeInt(u32, elf.GRP_COMDAT, .little);1697 try writer.writeInt(u32, elf.GRP_COMDAT, .little);
1704 for (members) |shndx| {1698 for (members) |shndx| {
test/link/elf.zig+38-6
...@@ -404,9 +404,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -404,9 +404,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
404 main_o.linkLibCpp();404 main_o.linkLibCpp();
405405
406 {406 {
407 const exe = addExecutable(b, opts, .{407 const exe = addExecutable(b, opts, .{ .name = "main1" });
408 .name = "main1",
409 });
410 exe.addObject(a_o);408 exe.addObject(a_o);
411 exe.addObject(main_o);409 exe.addObject(main_o);
412 exe.linkLibCpp();410 exe.linkLibCpp();
...@@ -431,9 +429,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -431,9 +429,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
431 }429 }
432430
433 {431 {
434 const exe = addExecutable(b, opts, .{432 const exe = addExecutable(b, opts, .{ .name = "main2" });
435 .name = "main2",
436 });
437 exe.addObject(main_o);433 exe.addObject(main_o);
438 exe.addObject(a_o);434 exe.addObject(a_o);
439 exe.linkLibCpp();435 exe.linkLibCpp();
...@@ -457,6 +453,42 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -457,6 +453,42 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
457 test_step.dependOn(&check.step);453 test_step.dependOn(&check.step);
458 }454 }
459455
456 {
457 const c_o = addObject(b, opts, .{ .name = "c" });
458 c_o.addObject(main_o);
459 c_o.addObject(a_o);
460
461 const exe = addExecutable(b, opts, .{ .name = "main3" });
462 exe.addObject(c_o);
463 exe.linkLibCpp();
464
465 const run = addRunArtifact(exe);
466 run.expectStdOutEqual(
467 \\calling foo in main
468 \\calling foo in main
469 \\
470 );
471 test_step.dependOn(&run.step);
472 }
473
474 {
475 const d_o = addObject(b, opts, .{ .name = "d" });
476 d_o.addObject(a_o);
477 d_o.addObject(main_o);
478
479 const exe = addExecutable(b, opts, .{ .name = "main4" });
480 exe.addObject(d_o);
481 exe.linkLibCpp();
482
483 const run = addRunArtifact(exe);
484 run.expectStdOutEqual(
485 \\calling foo in a
486 \\calling foo in a
487 \\
488 );
489 test_step.dependOn(&run.step);
490 }
491
460 return test_step;492 return test_step;
461}493}
462494