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.
This commit is contained in:
Jacob Young 2025-06-09 18:38:39 -04:00
parent e92b129063
commit ed37a1a33c
3 changed files with 61 additions and 6 deletions

View file

@ -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| {

View file

@ -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,

View file

@ -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(