Commit ed37a1a33c

Jacob Young <jacobly0@users.noreply.github.com>
2025-06-10 00:38:39
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.
1 parent e92b129
Changed files (3)
lib
compiler_rt
src
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| {
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(
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,