| author | |
| committer | |
| log | 0227253677e6579deb1849554638fd9d8f20d9e3 |
| tree | 1bd5428a2514140a27bf109d9f4f64b60afee512 |
| parent | 39064347460d1f8cd72ada1e77618fc2b83f8d0d |
| signature |
libtsan contains a .preinit_array entry that must run for correctness.7 files changed, 54 insertions(+), 42 deletions(-)
src/Compilation.zig+6-4| ... | ... | @@ -7426,7 +7426,7 @@ fn buildOutputFromZig( |
| 7426 | 7426 | assert(out.* == null); |
| 7427 | 7427 | out.* = crt_file; |
| 7428 | 7428 | |
| 7429 | try comp.queuePrelinkTaskMode(crt_file.full_object_path, &config); | |
| 7429 | try comp.queuePrelinkTaskMode(crt_file.full_object_path, false, &config); | |
| 7430 | 7430 | } |
| 7431 | 7431 | |
| 7432 | 7432 | pub const CrtFileOptions = struct { |
| ... | ... | @@ -7560,7 +7560,7 @@ pub fn build_crt_file( |
| 7560 | 7560 | try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); |
| 7561 | 7561 | |
| 7562 | 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); | |
| 7564 | 7564 | |
| 7565 | 7565 | { |
| 7566 | 7566 | comp.mutex.lockUncancelable(io); |
| ... | ... | @@ -7570,12 +7570,14 @@ pub fn build_crt_file( |
| 7570 | 7570 | } |
| 7571 | 7571 | } |
| 7572 | 7572 | |
| 7573 | pub 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. | |
| 7575 | pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, must_link: bool, config: *const Compilation.Config) Io.Cancelable!void { | |
| 7574 | 7576 | try comp.queuePrelinkTasks(switch (config.output_mode) { |
| 7575 | 7577 | .Exe => unreachable, |
| 7576 | 7578 | .Obj => &.{.{ .load_object = path }}, |
| 7577 | 7579 | .Lib => &.{switch (config.link_mode) { |
| 7578 | .static => .{ .load_archive = path }, | |
| 7580 | .static => .{ .load_archive = .{ .path = path, .must_link = must_link } }, | |
| 7579 | 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 | 295 | assert(comp.libcxx_static_lib == null); |
| 296 | 296 | const crt_file = try sub_compilation.toCrtFile(); |
| 297 | 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 | } |
| 300 | 300 | |
| 301 | 301 | pub 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 | 492 | assert(comp.libcxxabi_static_lib == null); |
| 493 | 493 | const crt_file = try sub_compilation.toCrtFile(); |
| 494 | 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 | } |
| 497 | 497 | |
| 498 | 498 | pub 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 | 320 | }, |
| 321 | 321 | }; |
| 322 | 322 | |
| 323 | // libtsan contains `.preinit_array` entries that must run for correctness, hence `must_link = true`. | |
| 323 | 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 | 326 | assert(comp.tsan_lib == null); |
| 326 | 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 | 179 | }; |
| 180 | 180 | |
| 181 | 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 | 183 | assert(comp.libunwind_static_lib == null); |
| 184 | 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 | 279 | errdefer comp.gpa.free(basename); |
| 280 | 280 | |
| 281 | 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 | 284 | comp.mutex.lockUncancelable(io); |
| 285 | 285 | defer comp.mutex.unlock(io); |
src/link.zig+31-26| ... | ... | @@ -1105,27 +1105,29 @@ pub const File = struct { |
| 1105 | 1105 | } |
| 1106 | 1106 | |
| 1107 | 1107 | /// Opens a path as a static library and parses it into the linker. |
| 1108 | /// If `query` is non-null, allows GNU ld scripts. | |
| 1109 | fn openLoadArchive(base: *File, path: Path, opt_query: ?UnresolvedInput.Query) anyerror!void { | |
| 1108 | fn openLoadArchive(base: *File, path: Path, must_link: bool) anyerror!void { | |
| 1110 | 1109 | if (base.tag == .lld) return; |
| 1111 | 1110 | const io = base.comp.io; |
| 1112 | if (opt_query) |query| { | |
| 1113 | const archive = try openObject(io, path, query.must_link, query.hidden); | |
| 1114 | errdefer archive.file.close(io); | |
| 1115 | loadInput(base, .{ .archive = archive }) catch |err| switch (err) { | |
| 1116 | error.BadMagic, error.UnexpectedEndOfFile => { | |
| 1117 | if (base.tag != .elf and base.tag != .elf2) return err; | |
| 1118 | try loadGnuLdScript(base, path, query, archive.file); | |
| 1119 | archive.file.close(io); | |
| 1120 | return; | |
| 1121 | }, | |
| 1122 | else => return err, | |
| 1123 | }; | |
| 1124 | } else { | |
| 1125 | const archive = try openObject(io, path, false, false); | |
| 1126 | errdefer archive.file.close(io); | |
| 1127 | try loadInput(base, .{ .archive = archive }); | |
| 1128 | } | |
| 1111 | const archive = try openObject(io, path, must_link, false); | |
| 1112 | errdefer archive.file.close(io); | |
| 1113 | try loadInput(base, .{ .archive = archive }); | |
| 1114 | } | |
| 1115 | ||
| 1116 | /// Opens a path as a static library and parses it into the linker. Allows GNU ld scripts. | |
| 1117 | fn openLoadArchiveQuery(base: *File, path: Path, query: UnresolvedInput.Query) anyerror!void { | |
| 1118 | if (base.tag == .lld) return; | |
| 1119 | const io = base.comp.io; | |
| 1120 | const archive = try openObject(io, path, query.must_link, query.hidden); | |
| 1121 | errdefer archive.file.close(io); | |
| 1122 | loadInput(base, .{ .archive = archive }) catch |err| switch (err) { | |
| 1123 | error.BadMagic, error.UnexpectedEndOfFile => { | |
| 1124 | if (base.tag != .elf and base.tag != .elf2) return err; | |
| 1125 | try loadGnuLdScript(base, path, query, archive.file); | |
| 1126 | archive.file.close(io); | |
| 1127 | return; | |
| 1128 | }, | |
| 1129 | else => return err, | |
| 1130 | }; | |
| 1129 | 1131 | } |
| 1130 | 1132 | |
| 1131 | 1133 | /// Opens a path as a shared library and parses it into the linker. |
| ... | ... | @@ -1180,7 +1182,7 @@ pub const File = struct { |
| 1180 | 1182 | switch (Compilation.classifyFileExt(arg.path)) { |
| 1181 | 1183 | .shared_library => try openLoadDso(base, new_path, query), |
| 1182 | 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 | 1186 | else => diags.addParseError(path, "GNU ld script references file with unrecognized extension: {s}", .{arg.path}), |
| 1185 | 1187 | } |
| 1186 | 1188 | } else { |
| ... | ... | @@ -1380,7 +1382,10 @@ pub const PrelinkTask = union(enum) { |
| 1380 | 1382 | /// Tells the linker to load an object file by path. |
| 1381 | 1383 | load_object: Path, |
| 1382 | 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 | 1389 | /// Tells the linker to load a shared library, possibly one that is a |
| 1385 | 1390 | /// GNU ld script. |
| 1386 | 1391 | load_dso: Path, |
| ... | ... | @@ -1462,7 +1467,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { |
| 1462 | 1467 | crt_dir, target.libPrefix(), lib_name, target.staticLibSuffix(), |
| 1463 | 1468 | }) catch return diags.setAllocFailure(), |
| 1464 | 1469 | ); |
| 1465 | base.openLoadArchive(archive_path, .{ | |
| 1470 | base.openLoadArchiveQuery(archive_path, .{ | |
| 1466 | 1471 | .preferred_mode = .dynamic, |
| 1467 | 1472 | .search_strategy = .paths_first, |
| 1468 | 1473 | }) catch |archive_err| switch (archive_err) { |
| ... | ... | @@ -1481,7 +1486,7 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { |
| 1481 | 1486 | }) catch return diags.setAllocFailure(), |
| 1482 | 1487 | ); |
| 1483 | 1488 | // glibc sometimes makes even archive files GNU ld scripts. |
| 1484 | base.openLoadArchive(path, .{ | |
| 1489 | base.openLoadArchiveQuery(path, .{ | |
| 1485 | 1490 | .preferred_mode = .static, |
| 1486 | 1491 | .search_strategy = .no_fallback, |
| 1487 | 1492 | }) catch |err| switch (err) { |
| ... | ... | @@ -1500,12 +1505,12 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { |
| 1500 | 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 | 1509 | const prog_node = comp.link_prog_node.start("Parse Archive", 0); |
| 1505 | 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 | 1512 | 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 | 1516 | .load_dso => |path| { |
src/link/Lld.zig+11-7| ... | ... | @@ -1086,10 +1086,10 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { |
| 1086 | 1086 | .dso => continue, |
| 1087 | 1087 | .object, .archive => |obj| { |
| 1088 | 1088 | if (obj.must_link and !whole_archive) { |
| 1089 | try argv.append("-whole-archive"); | |
| 1089 | try argv.append("--whole-archive"); | |
| 1090 | 1090 | whole_archive = true; |
| 1091 | 1091 | } else if (!obj.must_link and whole_archive) { |
| 1092 | try argv.append("-no-whole-archive"); | |
| 1092 | try argv.append("--no-whole-archive"); | |
| 1093 | 1093 | whole_archive = false; |
| 1094 | 1094 | } |
| 1095 | 1095 | try argv.append(try obj.path.toString(arena)); |
| ... | ... | @@ -1101,7 +1101,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { |
| 1101 | 1101 | }; |
| 1102 | 1102 | |
| 1103 | 1103 | if (whole_archive) { |
| 1104 | try argv.append("-no-whole-archive"); | |
| 1104 | try argv.append("--no-whole-archive"); | |
| 1105 | 1105 | whole_archive = false; |
| 1106 | 1106 | } |
| 1107 | 1107 | |
| ... | ... | @@ -1115,7 +1115,11 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { |
| 1115 | 1115 | |
| 1116 | 1116 | if (comp.tsan_lib) |lib| { |
| 1117 | 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 | } |
| 1120 | 1124 | |
| 1121 | 1125 | if (comp.fuzzer_lib) |lib| { |
| ... | ... | @@ -1549,10 +1553,10 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { |
| 1549 | 1553 | for (comp.link_inputs) |link_input| switch (link_input) { |
| 1550 | 1554 | .object, .archive => |obj| { |
| 1551 | 1555 | if (obj.must_link and !whole_archive) { |
| 1552 | try argv.append("-whole-archive"); | |
| 1556 | try argv.append("--whole-archive"); | |
| 1553 | 1557 | whole_archive = true; |
| 1554 | 1558 | } else if (!obj.must_link and whole_archive) { |
| 1555 | try argv.append("-no-whole-archive"); | |
| 1559 | try argv.append("--no-whole-archive"); | |
| 1556 | 1560 | whole_archive = false; |
| 1557 | 1561 | } |
| 1558 | 1562 | try argv.append(try obj.path.toString(arena)); |
| ... | ... | @@ -1564,7 +1568,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { |
| 1564 | 1568 | .res => unreachable, |
| 1565 | 1569 | }; |
| 1566 | 1570 | if (whole_archive) { |
| 1567 | try argv.append("-no-whole-archive"); | |
| 1571 | try argv.append("--no-whole-archive"); | |
| 1568 | 1572 | whole_archive = false; |
| 1569 | 1573 | } |
| 1570 | 1574 |