Elf2: start implementing dynamic linking

This commit is contained in:
Jacob Young 2025-10-29 18:04:11 -04:00
parent 40901440a6
commit 0834e696f7
11 changed files with 625 additions and 226 deletions

View File

@ -596,10 +596,13 @@ pub fn appendZigProcessFlags(
"-target", try target.query.zigTriple(b.allocator), "-target", try target.query.zigTriple(b.allocator),
"-mcpu", try target.query.serializeCpuAlloc(b.allocator), "-mcpu", try target.query.serializeCpuAlloc(b.allocator),
}); });
if (target.query.dynamic_linker) |dynamic_linker| {
if (target.query.dynamic_linker.get()) |dynamic_linker| { if (dynamic_linker.get()) |dynamic_linker_path| {
try zig_args.append("--dynamic-linker"); try zig_args.append("--dynamic-linker");
try zig_args.append(dynamic_linker); try zig_args.append(dynamic_linker_path);
} else {
try zig_args.append("--no-dynamic-linker");
}
} }
} }
} }

View File

@ -46,8 +46,9 @@ android_api_level: ?u32 = null,
abi: ?Target.Abi = null, abi: ?Target.Abi = null,
/// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path /// When `os_tag` is `null`, then `null` means native. Otherwise it means the standard path
/// based on the `os_tag`. /// based on the `os_tag`. When `dynamic_linker` is a non-`null` empty string, no dynamic
dynamic_linker: Target.DynamicLinker = .none, /// linker is used regardless of `os_tag`.
dynamic_linker: ?Target.DynamicLinker = null,
/// `null` means default for the cpu/arch/os combo. /// `null` means default for the cpu/arch/os combo.
ofmt: ?Target.ObjectFormat = null, ofmt: ?Target.ObjectFormat = null,
@ -213,7 +214,7 @@ pub fn parse(args: ParseOptions) !Query {
const diags = args.diagnostics orelse &dummy_diags; const diags = args.diagnostics orelse &dummy_diags;
var result: Query = .{ var result: Query = .{
.dynamic_linker = Target.DynamicLinker.init(args.dynamic_linker), .dynamic_linker = if (args.dynamic_linker) |dynamic_linker| .init(dynamic_linker) else null,
}; };
var it = mem.splitScalar(u8, args.arch_os_abi, '-'); var it = mem.splitScalar(u8, args.arch_os_abi, '-');
@ -381,7 +382,7 @@ pub fn isNativeCpu(self: Query) bool {
pub fn isNativeOs(self: Query) bool { pub fn isNativeOs(self: Query) bool {
return self.os_tag == null and self.os_version_min == null and self.os_version_max == null and return self.os_tag == null and self.os_version_min == null and self.os_version_max == null and
self.dynamic_linker.get() == null and self.glibc_version == null and self.android_api_level == null; self.dynamic_linker == null and self.glibc_version == null and self.android_api_level == null;
} }
pub fn isNativeAbi(self: Query) bool { pub fn isNativeAbi(self: Query) bool {
@ -599,7 +600,7 @@ pub fn eql(a: Query, b: Query) bool {
if (!versionEqualOpt(a.glibc_version, b.glibc_version)) return false; if (!versionEqualOpt(a.glibc_version, b.glibc_version)) return false;
if (a.android_api_level != b.android_api_level) return false; if (a.android_api_level != b.android_api_level) return false;
if (a.abi != b.abi) return false; if (a.abi != b.abi) return false;
if (!a.dynamic_linker.eql(b.dynamic_linker)) return false; if (!dynamicLinkerEqualOpt(a.dynamic_linker, b.dynamic_linker)) return false;
if (a.ofmt != b.ofmt) return false; if (a.ofmt != b.ofmt) return false;
return true; return true;
@ -611,6 +612,12 @@ fn versionEqualOpt(a: ?SemanticVersion, b: ?SemanticVersion) bool {
return SemanticVersion.order(a.?, b.?) == .eq; return SemanticVersion.order(a.?, b.?) == .eq;
} }
fn dynamicLinkerEqualOpt(a: ?Target.DynamicLinker, b: ?Target.DynamicLinker) bool {
if (a == null and b == null) return true;
if (a == null or b == null) return false;
return a.?.eql(b.?);
}
test parse { test parse {
const io = std.testing.io; const io = std.testing.io;

View File

@ -7013,7 +7013,8 @@ pub const RTLD = switch (native_os) {
LAZY: bool = false, LAZY: bool = false,
NOW: bool = false, NOW: bool = false,
NOLOAD: bool = false, NOLOAD: bool = false,
_3: u5 = 0, DEEPBIND: bool = false,
_4: u4 = 0,
GLOBAL: bool = false, GLOBAL: bool = false,
_9: u3 = 0, _9: u3 = 0,
NODELETE: bool = false, NODELETE: bool = false,

View File

@ -562,7 +562,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
// Apply the initial relocations as early as possible in the startup process. We cannot // Apply the initial relocations as early as possible in the startup process. We cannot
// make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet, // make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet,
// so this must be fully inlined. // so this must be fully inlined.
if (builtin.position_independent_executable) { if (builtin.link_mode == .static and builtin.position_independent_executable) {
@call(.always_inline, std.pie.relocate, .{phdrs}); @call(.always_inline, std.pie.relocate, .{phdrs});
} }

View File

@ -585,10 +585,10 @@ fn abiAndDynamicLinkerFromFile(
.os = os, .os = os,
.abi = query.abi orelse Target.Abi.default(cpu.arch, os.tag), .abi = query.abi orelse Target.Abi.default(cpu.arch, os.tag),
.ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch), .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
.dynamic_linker = query.dynamic_linker, .dynamic_linker = query.dynamic_linker orelse .none,
}; };
var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC
const look_for_ld = query.dynamic_linker.get() == null; const look_for_ld = query.dynamic_linker == null;
var got_dyn_section: bool = false; var got_dyn_section: bool = false;
{ {
@ -938,7 +938,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ
const is_linux = builtin.target.os.tag == .linux; const is_linux = builtin.target.os.tag == .linux;
const is_illumos = builtin.target.os.tag == .illumos; const is_illumos = builtin.target.os.tag == .illumos;
const is_darwin = builtin.target.os.tag.isDarwin(); const is_darwin = builtin.target.os.tag.isDarwin();
const have_all_info = query.dynamic_linker.get() != null and const have_all_info = query.dynamic_linker != null and
query.abi != null and (!is_linux or query.abi.?.isGnu()); query.abi != null and (!is_linux or query.abi.?.isGnu());
const os_is_non_native = query.os_tag != null; const os_is_non_native = query.os_tag != null;
// The illumos environment is always the same. // The illumos environment is always the same.
@ -1126,10 +1126,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Quer
.os = os, .os = os,
.abi = abi, .abi = abi,
.ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch), .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
.dynamic_linker = if (query.dynamic_linker.get() == null) .dynamic_linker = query.dynamic_linker orelse .standard(cpu, os, abi),
Target.DynamicLinker.standard(cpu, os, abi)
else
query.dynamic_linker,
}; };
} }

View File

@ -123,6 +123,7 @@ pub const ResolveError = error{
WasiExecModelRequiresWasi, WasiExecModelRequiresWasi,
SharedMemoryIsWasmOnly, SharedMemoryIsWasmOnly,
ObjectFilesCannotShareMemory, ObjectFilesCannotShareMemory,
ObjectFilesCannotSpecifyDynamicLinker,
SharedMemoryRequiresAtomicsAndBulkMemory, SharedMemoryRequiresAtomicsAndBulkMemory,
ThreadsRequireSharedMemory, ThreadsRequireSharedMemory,
EmittingLlvmModuleRequiresLlvmBackend, EmittingLlvmModuleRequiresLlvmBackend,
@ -131,6 +132,7 @@ pub const ResolveError = error{
EmittingBinaryRequiresLlvmLibrary, EmittingBinaryRequiresLlvmLibrary,
LldIncompatibleObjectFormat, LldIncompatibleObjectFormat,
LldCannotIncrementallyLink, LldCannotIncrementallyLink,
LldCannotSpecifyDynamicLinkerForSharedLibraries,
LtoRequiresLld, LtoRequiresLld,
SanitizeThreadRequiresLibCpp, SanitizeThreadRequiresLibCpp,
LibCRequiresLibUnwind, LibCRequiresLibUnwind,
@ -142,6 +144,7 @@ pub const ResolveError = error{
TargetCannotStaticLinkExecutables, TargetCannotStaticLinkExecutables,
LibCRequiresDynamicLinking, LibCRequiresDynamicLinking,
SharedLibrariesRequireDynamicLinking, SharedLibrariesRequireDynamicLinking,
DynamicLinkingWithLldRequiresSharedLibraries,
ExportMemoryAndDynamicIncompatible, ExportMemoryAndDynamicIncompatible,
DynamicLibraryPrecludesPie, DynamicLibraryPrecludesPie,
TargetRequiresPie, TargetRequiresPie,
@ -274,16 +277,11 @@ pub fn resolve(options: Options) ResolveError!Config {
if (options.link_mode == .static) return error.LibCRequiresDynamicLinking; if (options.link_mode == .static) return error.LibCRequiresDynamicLinking;
break :b .dynamic; break :b .dynamic;
} }
// When creating a executable that links to system libraries, we
// require dynamic linking, but we must not link static libraries
// or object files dynamically!
if (options.any_dyn_libs and options.output_mode == .Exe) {
if (options.link_mode == .static) return error.SharedLibrariesRequireDynamicLinking;
break :b .dynamic;
}
if (options.link_mode) |link_mode| break :b link_mode; if (options.link_mode) |link_mode| break :b link_mode;
if (options.any_dyn_libs) break :b .dynamic;
if (explicitly_exe_or_dyn_lib and link_libc) { if (explicitly_exe_or_dyn_lib and link_libc) {
// When using the native glibc/musl ABI, dynamic linking is usually what people want. // When using the native glibc/musl ABI, dynamic linking is usually what people want.
if (options.resolved_target.is_native_abi and (target.isGnuLibC() or target.isMuslLibC())) { if (options.resolved_target.is_native_abi and (target.isGnuLibC() or target.isMuslLibC())) {
@ -425,6 +423,25 @@ pub fn resolve(options: Options) ResolveError!Config {
break :b use_llvm; break :b use_llvm;
}; };
switch (options.output_mode) {
.Exe => if (options.any_dyn_libs) {
// When creating a executable that links to system libraries, we
// require dynamic linking, but we must not link static libraries
// or object files dynamically!
if (link_mode == .static) return error.SharedLibrariesRequireDynamicLinking;
} else if (use_lld and !link_libc and !link_libcpp and !link_libunwind) {
// Lld does not support creating dynamic executables when not
// linking to any shared libraries.
if (link_mode == .dynamic) return error.DynamicLinkingWithLldRequiresSharedLibraries;
},
.Lib => if (use_lld and options.resolved_target.is_explicit_dynamic_linker) {
return error.LldCannotSpecifyDynamicLinkerForSharedLibraries;
},
.Obj => if (options.resolved_target.is_explicit_dynamic_linker) {
return error.ObjectFilesCannotSpecifyDynamicLinker;
},
}
const use_new_linker = b: { const use_new_linker = b: {
if (use_lld) { if (use_lld) {
if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld; if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld;

View File

@ -182,6 +182,10 @@ pub fn emitMir(emit: *Emit) Error!void {
try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{ else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
.name = extern_func.toSlice(&emit.lower.mir).?, .name = extern_func.toSlice(&emit.lower.mir).?,
.lib_name = switch (comp.compiler_rt_strat) {
.none, .lib, .obj, .zcu => null,
.dyn_lib => "compiler_rt",
},
.type = .FUNC, .type = .FUNC,
})) else if (emit.bin_file.cast(.macho)) |macho_file| })) else if (emit.bin_file.cast(.macho)) |macho_file|
try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)
@ -320,10 +324,12 @@ pub fn emitMir(emit: *Emit) Error!void {
}, emit.lower.target), &.{.{ }, emit.lower.target), &.{.{
.op_index = 0, .op_index = 0,
.target = .{ .target = .{
.index = if (emit.bin_file.cast(.elf)) |elf_file| .index = if (emit.bin_file.cast(.elf)) |elf_file| try elf_file.getGlobalSymbol(
try elf_file.getGlobalSymbol("__tls_get_addr", null) "__tls_get_addr",
else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{ if (comp.config.link_libc) "c" else null,
) else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{
.name = "__tls_get_addr", .name = "__tls_get_addr",
.lib_name = if (comp.config.link_libc) "c" else null,
.type = .FUNC, .type = .FUNC,
})) else unreachable, })) else unreachable,
.is_extern = true, .is_extern = true,

View File

@ -1882,17 +1882,13 @@ fn initSyntheticSections(self: *Elf) !void {
const comp = self.base.comp; const comp = self.base.comp;
const target = self.getTarget(); const target = self.getTarget();
const ptr_size = self.ptrWidthBytes(); const ptr_size = self.ptrWidthBytes();
const shared_objects = self.shared_objects.values();
const is_exe_or_dyn_lib = switch (comp.config.output_mode) { const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
.Exe => true, .Exe => true,
.Lib => comp.config.link_mode == .dynamic, .Lib => comp.config.link_mode == .dynamic,
.Obj => false, .Obj => false,
}; };
const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none); const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib;
const needs_interp = have_dynamic_linker and
(comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker);
const needs_eh_frame = blk: { const needs_eh_frame = blk: {
if (self.zigObjectPtr()) |zo| if (self.zigObjectPtr()) |zo|
@ -2004,7 +2000,15 @@ fn initSyntheticSections(self: *Elf) !void {
}); });
} }
if (needs_interp and self.section_indexes.interp == null) { if (needs_interp: {
if (comp.config.link_mode == .static) break :needs_interp false;
if (target.dynamic_linker.get() == null) break :needs_interp false;
break :needs_interp switch (comp.config.output_mode) {
.Exe => true,
.Lib => comp.root_mod.resolved_target.is_explicit_dynamic_linker,
.Obj => false,
};
} and self.section_indexes.interp == null) {
self.section_indexes.interp = try self.addSection(.{ self.section_indexes.interp = try self.addSection(.{
.name = try self.insertShString(".interp"), .name = try self.insertShString(".interp"),
.type = elf.SHT_PROGBITS, .type = elf.SHT_PROGBITS,
@ -2013,7 +2017,7 @@ fn initSyntheticSections(self: *Elf) !void {
}); });
} }
if (self.isEffectivelyDynLib() or shared_objects.len > 0 or comp.config.pie) { if (have_dynamic_linker or comp.config.pie or self.isEffectivelyDynLib()) {
if (self.section_indexes.dynstrtab == null) { if (self.section_indexes.dynstrtab == null) {
self.section_indexes.dynstrtab = try self.addSection(.{ self.section_indexes.dynstrtab = try self.addSection(.{
.name = try self.insertShString(".dynstr"), .name = try self.insertShString(".dynstr"),

File diff suppressed because it is too large Load Diff

View File

@ -808,7 +808,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
const link_mode = comp.config.link_mode; const link_mode = comp.config.link_mode;
const is_dyn_lib = link_mode == .dynamic and is_lib; const is_dyn_lib = link_mode == .dynamic and is_lib;
const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe; const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;
const have_dynamic_linker = link_mode == .dynamic and is_exe_or_dyn_lib;
const target = &comp.root_mod.resolved_target.result; const target = &comp.root_mod.resolved_target.result;
const compiler_rt_path: ?Cache.Path = blk: { const compiler_rt_path: ?Cache.Path = blk: {
if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
@ -1070,12 +1069,12 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
} }
} }
if (have_dynamic_linker and if (output_mode == .Exe and link_mode == .dynamic) {
(comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker))
{
if (target.dynamic_linker.get()) |dynamic_linker| { if (target.dynamic_linker.get()) |dynamic_linker| {
try argv.append("-dynamic-linker"); try argv.append("--dynamic-linker");
try argv.append(dynamic_linker); try argv.append(dynamic_linker);
} else {
try argv.append("--no-dynamic-linker");
} }
} }

View File

@ -558,6 +558,7 @@ const usage_build_generic =
\\ --enable-new-dtags Use the new behavior for dynamic tags (RUNPATH) \\ --enable-new-dtags Use the new behavior for dynamic tags (RUNPATH)
\\ --disable-new-dtags Use the old behavior for dynamic tags (RPATH) \\ --disable-new-dtags Use the old behavior for dynamic tags (RPATH)
\\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so) \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
\\ --no-dynamic-linker Do not set any dynamic interpreter path
\\ --sysroot [path] Set the system root directory (usually /) \\ --sysroot [path] Set the system root directory (usually /)
\\ --version [ver] Dynamic library semver \\ --version [ver] Dynamic library semver
\\ -fentry Enable entry point with default symbol name \\ -fentry Enable entry point with default symbol name
@ -1301,6 +1302,8 @@ fn buildOutputType(
mod_opts.optimize_mode = parseOptimizeMode(rest); mod_opts.optimize_mode = parseOptimizeMode(rest);
} else if (mem.eql(u8, arg, "--dynamic-linker")) { } else if (mem.eql(u8, arg, "--dynamic-linker")) {
create_module.dynamic_linker = args_iter.nextOrFatal(); create_module.dynamic_linker = args_iter.nextOrFatal();
} else if (mem.eql(u8, arg, "--no-dynamic-linker")) {
create_module.dynamic_linker = "";
} else if (mem.eql(u8, arg, "--sysroot")) { } else if (mem.eql(u8, arg, "--sysroot")) {
const next_arg = args_iter.nextOrFatal(); const next_arg = args_iter.nextOrFatal();
create_module.sysroot = next_arg; create_module.sysroot = next_arg;
@ -2418,6 +2421,11 @@ fn buildOutputType(
mem.eql(u8, arg, "-dynamic-linker")) mem.eql(u8, arg, "-dynamic-linker"))
{ {
create_module.dynamic_linker = linker_args_it.nextOrFatal(); create_module.dynamic_linker = linker_args_it.nextOrFatal();
} else if (mem.eql(u8, arg, "-I") or
mem.eql(u8, arg, "--no-dynamic-linker") or
mem.eql(u8, arg, "-no-dynamic-linker"))
{
create_module.dynamic_linker = "";
} else if (mem.eql(u8, arg, "-E") or } else if (mem.eql(u8, arg, "-E") or
mem.eql(u8, arg, "--export-dynamic") or mem.eql(u8, arg, "--export-dynamic") or
mem.eql(u8, arg, "-export-dynamic")) mem.eql(u8, arg, "-export-dynamic"))
@ -3191,13 +3199,14 @@ fn buildOutputType(
const resolved_soname: ?[]const u8 = switch (soname) { const resolved_soname: ?[]const u8 = switch (soname) {
.yes => |explicit| explicit, .yes => |explicit| explicit,
.no => null, .no => null,
.yes_default_value => switch (target.ofmt) { .yes_default_value => if (create_module.resolved_options.output_mode == .Lib and
.elf => if (have_version) create_module.resolved_options.link_mode == .dynamic and target.ofmt == .elf)
if (have_version)
try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major }) try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major })
else else
try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name}), try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name})
else => null, else
}, null,
}; };
const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) { const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) {
@ -3646,7 +3655,11 @@ fn buildOutputType(
try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu})); try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu}));
} }
if (create_module.dynamic_linker) |dl| { if (create_module.dynamic_linker) |dl| {
try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl }); if (dl.len > 0) {
try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl });
} else {
try test_exec_args.append(arena, "--no-dynamic-linker");
}
} }
try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file
} }
@ -3793,7 +3806,7 @@ fn createModule(
.result = target, .result = target,
.is_native_os = target_query.isNativeOs(), .is_native_os = target_query.isNativeOs(),
.is_native_abi = target_query.isNativeAbi(), .is_native_abi = target_query.isNativeAbi(),
.is_explicit_dynamic_linker = !target_query.dynamic_linker.eql(.none), .is_explicit_dynamic_linker = target_query.dynamic_linker != null,
}; };
}; };
@ -3965,6 +3978,7 @@ fn createModule(
error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}), error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}),
error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}), error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}),
error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}), error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}),
error.ObjectFilesCannotSpecifyDynamicLinker => fatal("object files cannot specify --dynamic-linker", .{}),
error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}), error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}),
error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}), error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}),
error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}), error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}),
@ -3973,6 +3987,7 @@ fn createModule(
error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}), error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}),
error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}), error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}),
error.LldCannotIncrementallyLink => fatal("self-hosted backends do not support linking with LLD", .{}), error.LldCannotIncrementallyLink => fatal("self-hosted backends do not support linking with LLD", .{}),
error.LldCannotSpecifyDynamicLinkerForSharedLibraries => fatal("LLD does not support --dynamic-linker on shared libraries", .{}),
error.LtoRequiresLld => fatal("LTO requires using LLD", .{}), error.LtoRequiresLld => fatal("LTO requires using LLD", .{}),
error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}), error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}),
error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}), error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}),
@ -3984,6 +3999,7 @@ fn createModule(
error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}), error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}),
error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}), error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}),
error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}), error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}),
error.DynamicLinkingWithLldRequiresSharedLibraries => fatal("dynamic linking with lld requires at least one shared library", .{}),
error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}), error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}),
error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}), error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}),
error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}), error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}),