authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-04-29 22:10:21+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-04-29 22:10:21+02:00
log2407ee954b780e5a6a73f88b0865feff365c5ce5
tree1bd5428a2514140a27bf109d9f4f64b60afee512
parentce198b7c28e89c0bb502d215f9f9de99abb25f08
parent0227253677e6579deb1849554638fd9d8f20d9e3

Merge pull request 'implement `.preinit_array` support in `link.Elf`; link libtsan with `-whole-archive`' (#32107) from alexrp/zig:preinit-array into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/32107 Reviewed-by: mlugg <mlugg@noreply.codeberg.org>

10 files changed, 71 insertions(+), 45 deletions(-)

src/Compilation.zig+6-4
...@@ -7426,7 +7426,7 @@ fn buildOutputFromZig(...@@ -7426,7 +7426,7 @@ fn buildOutputFromZig(
7426 assert(out.* == null);7426 assert(out.* == null);
7427 out.* = crt_file;7427 out.* = crt_file;
74287428
7429 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);7429 try comp.queuePrelinkTaskMode(crt_file.full_object_path, false, &config);
7430}7430}
74317431
7432pub const CrtFileOptions = struct {7432pub const CrtFileOptions = struct {
...@@ -7560,7 +7560,7 @@ pub fn build_crt_file(...@@ -7560,7 +7560,7 @@ pub fn build_crt_file(
7560 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);7560 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
75617561
7562 const crt_file = try sub_compilation.toCrtFile();7562 const crt_file = try sub_compilation.toCrtFile();
7563 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);7563 try comp.queuePrelinkTaskMode(crt_file.full_object_path, false, &config);
75647564
7565 {7565 {
7566 comp.mutex.lockUncancelable(io);7566 comp.mutex.lockUncancelable(io);
...@@ -7570,12 +7570,14 @@ pub fn build_crt_file(...@@ -7570,12 +7570,14 @@ pub fn build_crt_file(
7570 }7570 }
7571}7571}
75727572
7573pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const Compilation.Config) Io.Cancelable!void {7573/// If `must_link` is set, then static library inputs will have all member objects linked into the
7574/// output, instead of only those required to resolve symbol references.
7575pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, must_link: bool, config: *const Compilation.Config) Io.Cancelable!void {
7574 try comp.queuePrelinkTasks(switch (config.output_mode) {7576 try comp.queuePrelinkTasks(switch (config.output_mode) {
7575 .Exe => unreachable,7577 .Exe => unreachable,
7576 .Obj => &.{.{ .load_object = path }},7578 .Obj => &.{.{ .load_object = path }},
7577 .Lib => &.{switch (config.link_mode) {7579 .Lib => &.{switch (config.link_mode) {
7578 .static => .{ .load_archive = path },7580 .static => .{ .load_archive = .{ .path = path, .must_link = must_link } },
7579 .dynamic => .{ .load_dso = path },7581 .dynamic => .{ .load_dso = path },
7580 }},7582 }},
7581 });7583 });
src/libs/libcxx.zig+2-2
...@@ -295,7 +295,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!...@@ -295,7 +295,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
295 assert(comp.libcxx_static_lib == null);295 assert(comp.libcxx_static_lib == null);
296 const crt_file = try sub_compilation.toCrtFile();296 const crt_file = try sub_compilation.toCrtFile();
297 comp.libcxx_static_lib = crt_file;297 comp.libcxx_static_lib = crt_file;
298 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);298 try comp.queuePrelinkTaskMode(crt_file.full_object_path, false, &config);
299}299}
300300
301pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {301pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
...@@ -492,7 +492,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -492,7 +492,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
492 assert(comp.libcxxabi_static_lib == null);492 assert(comp.libcxxabi_static_lib == null);
493 const crt_file = try sub_compilation.toCrtFile();493 const crt_file = try sub_compilation.toCrtFile();
494 comp.libcxxabi_static_lib = crt_file;494 comp.libcxxabi_static_lib = crt_file;
495 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);495 try comp.queuePrelinkTaskMode(crt_file.full_object_path, false, &config);
496}496}
497497
498pub fn addCxxArgs(498pub fn addCxxArgs(
src/libs/libtsan.zig+2-1
...@@ -320,8 +320,9 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -320,8 +320,9 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
320 },320 },
321 };321 };
322322
323 // libtsan contains `.preinit_array` entries that must run for correctness, hence `must_link = true`.
323 const crt_file = try sub_compilation.toCrtFile();324 const crt_file = try sub_compilation.toCrtFile();
324 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);325 try comp.queuePrelinkTaskMode(crt_file.full_object_path, true, &config);
325 assert(comp.tsan_lib == null);326 assert(comp.tsan_lib == null);
326 comp.tsan_lib = crt_file;327 comp.tsan_lib = crt_file;
327}328}
src/libs/libunwind.zig+1-1
...@@ -179,7 +179,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -179,7 +179,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
179 };179 };
180180
181 const crt_file = try sub_compilation.toCrtFile();181 const crt_file = try sub_compilation.toCrtFile();
182 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);182 try comp.queuePrelinkTaskMode(crt_file.full_object_path, false, &config);
183 assert(comp.libunwind_static_lib == null);183 assert(comp.libunwind_static_lib == null);
184 comp.libunwind_static_lib = crt_file;184 comp.libunwind_static_lib = crt_file;
185}185}
src/libs/musl.zig+1-1
...@@ -279,7 +279,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro...@@ -279,7 +279,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
279 errdefer comp.gpa.free(basename);279 errdefer comp.gpa.free(basename);
280280
281 const crt_file = try sub_compilation.toCrtFile();281 const crt_file = try sub_compilation.toCrtFile();
282 try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config);282 try comp.queuePrelinkTaskMode(crt_file.full_object_path, false, &config);
283 {283 {
284 comp.mutex.lockUncancelable(io);284 comp.mutex.lockUncancelable(io);
285 defer comp.mutex.unlock(io);285 defer comp.mutex.unlock(io);
src/link.zig+31-26
...@@ -1105,27 +1105,29 @@ pub const File = struct {...@@ -1105,27 +1105,29 @@ pub const File = struct {
1105 }1105 }
11061106
1107 /// Opens a path as a static library and parses it into the linker.1107 /// Opens a path as a static library and parses it into the linker.
1108 /// If `query` is non-null, allows GNU ld scripts.1108 fn openLoadArchive(base: *File, path: Path, must_link: bool) anyerror!void {
1109 fn openLoadArchive(base: *File, path: Path, opt_query: ?UnresolvedInput.Query) anyerror!void {
1110 if (base.tag == .lld) return;1109 if (base.tag == .lld) return;
1111 const io = base.comp.io;1110 const io = base.comp.io;
1112 if (opt_query) |query| {1111 const archive = try openObject(io, path, must_link, false);
1113 const archive = try openObject(io, path, query.must_link, query.hidden);1112 errdefer archive.file.close(io);
1114 errdefer archive.file.close(io);1113 try loadInput(base, .{ .archive = archive });
1115 loadInput(base, .{ .archive = archive }) catch |err| switch (err) {1114 }
1116 error.BadMagic, error.UnexpectedEndOfFile => {1115
1117 if (base.tag != .elf and base.tag != .elf2) return err;1116 /// Opens a path as a static library and parses it into the linker. Allows GNU ld scripts.
1118 try loadGnuLdScript(base, path, query, archive.file);1117 fn openLoadArchiveQuery(base: *File, path: Path, query: UnresolvedInput.Query) anyerror!void {
1119 archive.file.close(io);1118 if (base.tag == .lld) return;
1120 return;1119 const io = base.comp.io;
1121 },1120 const archive = try openObject(io, path, query.must_link, query.hidden);
1122 else => return err,1121 errdefer archive.file.close(io);
1123 };1122 loadInput(base, .{ .archive = archive }) catch |err| switch (err) {
1124 } else {1123 error.BadMagic, error.UnexpectedEndOfFile => {
1125 const archive = try openObject(io, path, false, false);1124 if (base.tag != .elf and base.tag != .elf2) return err;
1126 errdefer archive.file.close(io);1125 try loadGnuLdScript(base, path, query, archive.file);
1127 try loadInput(base, .{ .archive = archive });1126 archive.file.close(io);
1128 }1127 return;
1128 },
1129 else => return err,
1130 };
1129 }1131 }
11301132
1131 /// Opens a path as a shared library and parses it into the linker.1133 /// Opens a path as a shared library and parses it into the linker.
...@@ -1180,7 +1182,7 @@ pub const File = struct {...@@ -1180,7 +1182,7 @@ pub const File = struct {
1180 switch (Compilation.classifyFileExt(arg.path)) {1182 switch (Compilation.classifyFileExt(arg.path)) {
1181 .shared_library => try openLoadDso(base, new_path, query),1183 .shared_library => try openLoadDso(base, new_path, query),
1182 .object => try openLoadObject(base, new_path),1184 .object => try openLoadObject(base, new_path),
1183 .static_library => try openLoadArchive(base, new_path, query),1185 .static_library => try openLoadArchiveQuery(base, new_path, query),
1184 else => diags.addParseError(path, "GNU ld script references file with unrecognized extension: {s}", .{arg.path}),1186 else => diags.addParseError(path, "GNU ld script references file with unrecognized extension: {s}", .{arg.path}),
1185 }1187 }
1186 } else {1188 } else {
...@@ -1380,7 +1382,10 @@ pub const PrelinkTask = union(enum) {...@@ -1380,7 +1382,10 @@ pub const PrelinkTask = union(enum) {
1380 /// Tells the linker to load an object file by path.1382 /// Tells the linker to load an object file by path.
1381 load_object: Path,1383 load_object: Path,
1382 /// Tells the linker to load a static library by path.1384 /// Tells the linker to load a static library by path.
1383 load_archive: Path,1385 load_archive: struct {
1386 path: Path,
1387 must_link: bool,
1388 },
1384 /// Tells the linker to load a shared library, possibly one that is a1389 /// Tells the linker to load a shared library, possibly one that is a
1385 /// GNU ld script.1390 /// GNU ld script.
1386 load_dso: Path,1391 load_dso: Path,
...@@ -1462,7 +1467,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {...@@ -1462,7 +1467,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
1462 crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(),1467 crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(),
1463 }) catch return diags.setAllocFailure(),1468 }) catch return diags.setAllocFailure(),
1464 );1469 );
1465 base.openLoadArchive(archive_path, .{1470 base.openLoadArchiveQuery(archive_path, .{
1466 .preferred_mode = .dynamic,1471 .preferred_mode = .dynamic,
1467 .search_strategy = .paths_first,1472 .search_strategy = .paths_first,
1468 }) catch |archive_err| switch (archive_err) {1473 }) catch |archive_err| switch (archive_err) {
...@@ -1481,7 +1486,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {...@@ -1481,7 +1486,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
1481 }) catch return diags.setAllocFailure(),1486 }) catch return diags.setAllocFailure(),
1482 );1487 );
1483 // glibc sometimes makes even archive files GNU ld scripts.1488 // glibc sometimes makes even archive files GNU ld scripts.
1484 base.openLoadArchive(path, .{1489 base.openLoadArchiveQuery(path, .{
1485 .preferred_mode = .static,1490 .preferred_mode = .static,
1486 .search_strategy = .no_fallback,1491 .search_strategy = .no_fallback,
1487 }) catch |err| switch (err) {1492 }) catch |err| switch (err) {
...@@ -1500,12 +1505,12 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {...@@ -1500,12 +1505,12 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
1500 else => |e| diags.addParseError(path, "failed to parse object: {s}", .{@errorName(e)}),1505 else => |e| diags.addParseError(path, "failed to parse object: {s}", .{@errorName(e)}),
1501 };1506 };
1502 },1507 },
1503 .load_archive => |path| {1508 .load_archive => |load_archive| {
1504 const prog_node = comp.link_prog_node.start("Parse Archive", 0);1509 const prog_node = comp.link_prog_node.start("Parse Archive", 0);
1505 defer prog_node.end();1510 defer prog_node.end();
1506 base.openLoadArchive(path, null) catch |err| switch (err) {1511 base.openLoadArchive(load_archive.path, load_archive.must_link) catch |err| switch (err) {
1507 error.LinkFailure => return, // error reported via link_diags1512 error.LinkFailure => return, // error reported via link_diags
1508 else => |e| diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}),1513 else => |e| diags.addParseError(load_archive.path, "failed to parse archive: {s}", .{@errorName(e)}),
1509 };1514 };
1510 },1515 },
1511 .load_dso => |path| {1516 .load_dso => |path| {
src/link/Elf.zig+5-3
...@@ -1392,9 +1392,9 @@ pub fn initOutputSection(self: *Elf, args: struct {...@@ -1392,9 +1392,9 @@ pub fn initOutputSection(self: *Elf, args: struct {
1392 if (self.base.isRelocatable()) break :blk args.name;1392 if (self.base.isRelocatable()) break :blk args.name;
1393 if (args.flags & elf.SHF_MERGE != 0) break :blk args.name;1393 if (args.flags & elf.SHF_MERGE != 0) break :blk args.name;
1394 const name_prefixes: []const [:0]const u8 = &.{1394 const name_prefixes: []const [:0]const u8 = &.{
1395 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",1395 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
1396 ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors",1396 ".preinit_array", ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table",
1397 ".dtors", ".gnu.warning",1397 ".ctors", ".dtors", ".gnu.warning",
1398 };1398 };
1399 inline for (name_prefixes) |prefix| {1399 inline for (name_prefixes) |prefix| {
1400 if (mem.eql(u8, args.name, prefix) or mem.startsWith(u8, args.name, prefix ++ ".")) {1400 if (mem.eql(u8, args.name, prefix) or mem.startsWith(u8, args.name, prefix ++ ".")) {
...@@ -1409,6 +1409,8 @@ pub fn initOutputSection(self: *Elf, args: struct {...@@ -1409,6 +1409,8 @@ pub fn initOutputSection(self: *Elf, args: struct {
1409 switch (args.type) {1409 switch (args.type) {
1410 elf.SHT_NULL => unreachable,1410 elf.SHT_NULL => unreachable,
1411 elf.SHT_PROGBITS => {1411 elf.SHT_PROGBITS => {
1412 if (mem.eql(u8, args.name, ".preinit_array") or mem.startsWith(u8, args.name, ".preinit_array."))
1413 break :tt elf.SHT_PREINIT_ARRAY;
1412 if (mem.eql(u8, args.name, ".init_array") or mem.startsWith(u8, args.name, ".init_array."))1414 if (mem.eql(u8, args.name, ".init_array") or mem.startsWith(u8, args.name, ".init_array."))
1413 break :tt elf.SHT_INIT_ARRAY;1415 break :tt elf.SHT_INIT_ARRAY;
1414 if (mem.eql(u8, args.name, ".fini_array") or mem.startsWith(u8, args.name, ".fini_array."))1416 if (mem.eql(u8, args.name, ".fini_array") or mem.startsWith(u8, args.name, ".fini_array."))
src/link/Elf/ZigObject.zig+4
...@@ -1237,6 +1237,10 @@ fn getNavShdrIndex(...@@ -1237,6 +1237,10 @@ fn getNavShdrIndex(
1237 self.debug_rnglists_index = section_index;1237 self.debug_rnglists_index = section_index;
1238 } else if (std.mem.startsWith(u8, section_name, ".debug")) {1238 } else if (std.mem.startsWith(u8, section_name, ".debug")) {
1239 elf_file.sections.items(.shdr)[osec].sh_flags = 0;1239 elf_file.sections.items(.shdr)[osec].sh_flags = 0;
1240 } else if (std.mem.eql(u8, section_name, ".preinit_array") or std.mem.startsWith(u8, section_name, ".preinit_array.")) {
1241 const shdr = &elf_file.sections.items(.shdr)[osec];
1242 shdr.sh_type = elf.SHT_PREINIT_ARRAY;
1243 shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE;
1240 } else if (std.mem.eql(u8, section_name, ".init_array") or std.mem.startsWith(u8, section_name, ".init_array.")) {1244 } else if (std.mem.eql(u8, section_name, ".init_array") or std.mem.startsWith(u8, section_name, ".init_array.")) {
1241 const shdr = &elf_file.sections.items(.shdr)[osec];1245 const shdr = &elf_file.sections.items(.shdr)[osec];
1242 shdr.sh_type = elf.SHT_INIT_ARRAY;1246 shdr.sh_type = elf.SHT_INIT_ARRAY;
src/link/Elf/synthetic_sections.zig+8
...@@ -73,6 +73,7 @@ pub const DynamicSection = struct {...@@ -73,6 +73,7 @@ pub const DynamicSection = struct {
73 if (dt.rpath > 0) nentries += 1; // RUNPATH73 if (dt.rpath > 0) nentries += 1; // RUNPATH
74 if (elf_file.sectionByName(".init") != null) nentries += 1; // INIT74 if (elf_file.sectionByName(".init") != null) nentries += 1; // INIT
75 if (elf_file.sectionByName(".fini") != null) nentries += 1; // FINI75 if (elf_file.sectionByName(".fini") != null) nentries += 1; // FINI
76 if (elf_file.sectionByName(".preinit_array") != null) nentries += 2; // PREINIT_ARRAY
76 if (elf_file.sectionByName(".init_array") != null) nentries += 2; // INIT_ARRAY77 if (elf_file.sectionByName(".init_array") != null) nentries += 2; // INIT_ARRAY
77 if (elf_file.sectionByName(".fini_array") != null) nentries += 2; // FINI_ARRAY78 if (elf_file.sectionByName(".fini_array") != null) nentries += 2; // FINI_ARRAY
78 if (elf_file.section_indexes.rela_dyn != null) nentries += 3; // RELA79 if (elf_file.section_indexes.rela_dyn != null) nentries += 3; // RELA
...@@ -124,6 +125,13 @@ pub const DynamicSection = struct {...@@ -124,6 +125,13 @@ pub const DynamicSection = struct {
124 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FINI, .d_val = addr }), .little);125 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FINI, .d_val = addr }), .little);
125 }126 }
126127
128 // PREINIT_ARRAY
129 if (elf_file.sectionByName(".preinit_array")) |shndx| {
130 const shdr = shdrs[shndx];
131 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_PREINIT_ARRAY, .d_val = shdr.sh_addr }), .little);
132 try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_PREINIT_ARRAYSZ, .d_val = shdr.sh_size }), .little);
133 }
134
127 // INIT_ARRAY135 // INIT_ARRAY
128 if (elf_file.sectionByName(".init_array")) |shndx| {136 if (elf_file.sectionByName(".init_array")) |shndx| {
129 const shdr = shdrs[shndx];137 const shdr = shdrs[shndx];
src/link/Lld.zig+11-7
...@@ -1086,10 +1086,10 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1086,10 +1086,10 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
1086 .dso => continue,1086 .dso => continue,
1087 .object, .archive => |obj| {1087 .object, .archive => |obj| {
1088 if (obj.must_link and !whole_archive) {1088 if (obj.must_link and !whole_archive) {
1089 try argv.append("-whole-archive");1089 try argv.append("--whole-archive");
1090 whole_archive = true;1090 whole_archive = true;
1091 } else if (!obj.must_link and whole_archive) {1091 } else if (!obj.must_link and whole_archive) {
1092 try argv.append("-no-whole-archive");1092 try argv.append("--no-whole-archive");
1093 whole_archive = false;1093 whole_archive = false;
1094 }1094 }
1095 try argv.append(try obj.path.toString(arena));1095 try argv.append(try obj.path.toString(arena));
...@@ -1101,7 +1101,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1101,7 +1101,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
1101 };1101 };
11021102
1103 if (whole_archive) {1103 if (whole_archive) {
1104 try argv.append("-no-whole-archive");1104 try argv.append("--no-whole-archive");
1105 whole_archive = false;1105 whole_archive = false;
1106 }1106 }
11071107
...@@ -1115,7 +1115,11 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1115,7 +1115,11 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
11151115
1116 if (comp.tsan_lib) |lib| {1116 if (comp.tsan_lib) |lib| {
1117 assert(comp.config.any_sanitize_thread);1117 assert(comp.config.any_sanitize_thread);
1118 try argv.append(try lib.full_object_path.toString(arena));1118 try argv.appendSlice(&.{
1119 "--whole-archive",
1120 try lib.full_object_path.toString(arena),
1121 "--no-whole-archive",
1122 });
1119 }1123 }
11201124
1121 if (comp.fuzzer_lib) |lib| {1125 if (comp.fuzzer_lib) |lib| {
...@@ -1549,10 +1553,10 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {...@@ -1549,10 +1553,10 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {
1549 for (comp.link_inputs) |link_input| switch (link_input) {1553 for (comp.link_inputs) |link_input| switch (link_input) {
1550 .object, .archive => |obj| {1554 .object, .archive => |obj| {
1551 if (obj.must_link and !whole_archive) {1555 if (obj.must_link and !whole_archive) {
1552 try argv.append("-whole-archive");1556 try argv.append("--whole-archive");
1553 whole_archive = true;1557 whole_archive = true;
1554 } else if (!obj.must_link and whole_archive) {1558 } else if (!obj.must_link and whole_archive) {
1555 try argv.append("-no-whole-archive");1559 try argv.append("--no-whole-archive");
1556 whole_archive = false;1560 whole_archive = false;
1557 }1561 }
1558 try argv.append(try obj.path.toString(arena));1562 try argv.append(try obj.path.toString(arena));
...@@ -1564,7 +1568,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {...@@ -1564,7 +1568,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {
1564 .res => unreachable,1568 .res => unreachable,
1565 };1569 };
1566 if (whole_archive) {1570 if (whole_archive) {
1567 try argv.append("-no-whole-archive");1571 try argv.append("--no-whole-archive");
1568 whole_archive = false;1572 whole_archive = false;
1569 }1573 }
15701574