From ed37a1a33c2576c00697643463a4720728e04023 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 9 Jun 2025 18:38:39 -0400 Subject: [PATCH] coff: add hack to build a compiler-rt dynamic library This is not meant to be a long-term solution, but it's the easiest thing to get working quickly at the moment. The main intention of this hack is to allow more tests to be enabled. By the time the coff linker is far enough along to be enabled by default, this will no longer be required. --- lib/compiler_rt/common.zig | 6 ++--- src/Compilation.zig | 46 +++++++++++++++++++++++++++++++++++--- src/link/Coff.zig | 15 +++++++++++++ 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/lib/compiler_rt/common.zig b/lib/compiler_rt/common.zig index 747e74841e..978e701130 100644 --- a/lib/compiler_rt/common.zig +++ b/lib/compiler_rt/common.zig @@ -16,10 +16,10 @@ else /// Determines the symbol's visibility to other objects. /// For WebAssembly this allows the symbol to be resolved to other modules, but will not /// export it to the host runtime. -pub const visibility: std.builtin.SymbolVisibility = if (linkage != .internal) - .hidden +pub const visibility: std.builtin.SymbolVisibility = if (linkage == .internal or builtin.link_mode == .dynamic) + .default else - .default; + .hidden; pub const PreferredLoadStoreElement = element: { if (std.simd.suggestVectorLength(u8)) |vec_size| { diff --git a/src/Compilation.zig b/src/Compilation.zig index e0f8cf5a56..4136b21f61 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -224,6 +224,8 @@ compiler_rt_lib: ?CrtFile = null, /// Populated when we build the compiler_rt_obj object. A Job to build this is indicated /// by setting `queued_jobs.compiler_rt_obj` and resolved before calling linker.flush(). compiler_rt_obj: ?CrtFile = null, +/// hack for stage2_x86_64 + coff +compiler_rt_dyn_lib: ?CrtFile = null, /// Populated when we build the libfuzzer static library. A Job to build this /// is indicated by setting `queued_jobs.fuzzer_lib` and resolved before /// calling linker.flush(). @@ -291,6 +293,8 @@ emit_llvm_bc: ?[]const u8, emit_docs: ?[]const u8, const QueuedJobs = struct { + /// hack for stage2_x86_64 + coff + compiler_rt_dyn_lib: bool = false, compiler_rt_lib: bool = false, compiler_rt_obj: bool = false, ubsan_rt_lib: bool = false, @@ -1753,7 +1757,7 @@ fn addModuleTableToCacheHash( } } -const RtStrat = enum { none, lib, obj, zcu }; +const RtStrat = enum { none, lib, obj, zcu, dyn_lib }; pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compilation { const output_mode = options.config.output_mode; @@ -1816,7 +1820,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil if (options.skip_linker_dependencies) break :s .none; const want = options.want_compiler_rt orelse is_exe_or_dyn_lib; if (!want) break :s .none; - if (have_zcu and output_mode == .Obj) break :s .zcu; + if (have_zcu) { + if (output_mode == .Obj) break :s .zcu; + if (target.ofmt == .coff and target_util.zigBackend(target, use_llvm) == .stage2_x86_64) + break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu; + } if (is_exe_or_dyn_lib) break :s .lib; break :s .obj; }; @@ -2441,6 +2449,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil // for a compiler-rt object to put in it. comp.queued_jobs.compiler_rt_obj = true; comp.link_task_queue.pending_prelink_tasks += 1; + } else if (comp.compiler_rt_strat == .dyn_lib) { + // hack for stage2_x86_64 + coff + log.debug("queuing a job to build compiler_rt_dyn_lib", .{}); + comp.queued_jobs.compiler_rt_dyn_lib = true; + comp.link_task_queue.pending_prelink_tasks += 1; } if (comp.ubsan_rt_strat == .lib) { @@ -4254,6 +4267,7 @@ fn performAllTheWork( "compiler_rt.zig", "compiler_rt", .Lib, + .static, .compiler_rt, main_progress_node, RtOptions{ @@ -4270,6 +4284,7 @@ fn performAllTheWork( "compiler_rt.zig", "compiler_rt", .Obj, + .static, .compiler_rt, main_progress_node, RtOptions{ @@ -4280,12 +4295,31 @@ fn performAllTheWork( }); } + // hack for stage2_x86_64 + coff + if (comp.queued_jobs.compiler_rt_dyn_lib and comp.compiler_rt_dyn_lib == null) { + comp.link_task_wait_group.spawnManager(buildRt, .{ + comp, + "compiler_rt.zig", + "compiler_rt", + .Lib, + .dynamic, + .compiler_rt, + main_progress_node, + RtOptions{ + .checks_valgrind = true, + .allow_lto = false, + }, + &comp.compiler_rt_dyn_lib, + }); + } + if (comp.queued_jobs.fuzzer_lib and comp.fuzzer_lib == null) { comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "fuzzer.zig", "fuzzer", .Lib, + .static, .libfuzzer, main_progress_node, RtOptions{}, @@ -4299,6 +4333,7 @@ fn performAllTheWork( "ubsan_rt.zig", "ubsan_rt", .Lib, + .static, .libubsan, main_progress_node, RtOptions{ @@ -4314,6 +4349,7 @@ fn performAllTheWork( "ubsan_rt.zig", "ubsan_rt", .Obj, + .static, .libubsan, main_progress_node, RtOptions{ @@ -5390,6 +5426,7 @@ fn buildRt( root_source_name: []const u8, root_name: []const u8, output_mode: std.builtin.OutputMode, + link_mode: std.builtin.LinkMode, misc_task: MiscTask, prog_node: std.Progress.Node, options: RtOptions, @@ -5399,6 +5436,7 @@ fn buildRt( root_source_name, root_name, output_mode, + link_mode, misc_task, prog_node, options, @@ -5554,6 +5592,7 @@ fn buildLibZigC(comp: *Compilation, prog_node: std.Progress.Node) void { "c.zig", "zigc", .Lib, + .static, .libzigc, prog_node, .{}, @@ -7231,6 +7270,7 @@ fn buildOutputFromZig( src_basename: []const u8, root_name: []const u8, output_mode: std.builtin.OutputMode, + link_mode: std.builtin.LinkMode, misc_task_tag: MiscTask, prog_node: std.Progress.Node, options: RtOptions, @@ -7251,7 +7291,7 @@ fn buildOutputFromZig( const config = try Config.resolve(.{ .output_mode = output_mode, - .link_mode = .static, + .link_mode = link_mode, .resolved_target = comp.root_mod.resolved_target, .is_test = false, .have_zcu = true, diff --git a/src/link/Coff.zig b/src/link/Coff.zig index d774f14bf6..2ca7ec6de0 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1715,6 +1715,21 @@ fn flushInner(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id) !void { } assert(!coff.imports_count_dirty); + + // hack for stage2_x86_64 + coff + if (comp.compiler_rt_dyn_lib) |crt_file| { + const compiler_rt_sub_path = try std.fs.path.join(gpa, &.{ + std.fs.path.dirname(coff.base.emit.sub_path) orelse "", + std.fs.path.basename(crt_file.full_object_path.sub_path), + }); + defer gpa.free(compiler_rt_sub_path); + try crt_file.full_object_path.root_dir.handle.copyFile( + crt_file.full_object_path.sub_path, + coff.base.emit.root_dir.handle, + compiler_rt_sub_path, + .{}, + ); + } } pub fn getNavVAddr(