From 8af82621d75f9f0d96ebf734f5ea862d06a5f1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 13 Nov 2024 06:04:04 +0100 Subject: [PATCH] compiler: Improve the handling of unwind table levels. The goal here is to support both levels of unwind tables (sync and async) in zig cc and zig build. Previously, the LLVM backend always used async tables while zig cc was partially influenced by whatever was Clang's default. --- lib/std/Build.zig | 10 ++--- lib/std/Build/Module.zig | 13 ++++-- lib/std/builtin.zig | 8 ++++ src/Builtin.zig | 3 ++ src/Compilation.zig | 27 +++++++++--- src/Compilation/Config.zig | 24 ++++++----- src/Package/Module.zig | 7 +-- src/clang_options_data.zig | 18 +++++++- src/codegen/llvm.zig | 7 ++- src/libcxx.zig | 9 ++-- src/libunwind.zig | 3 +- src/main.zig | 54 ++++++++++++++++++++---- src/mingw.zig | 17 ++++++-- src/target.zig | 13 +++++- test/standalone/stack_iterator/build.zig | 6 +-- tools/update_clang_options.zig | 8 ++++ 16 files changed, 174 insertions(+), 53 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 041de3e06f1b06472d412368cc458081048cf001..65e2db3d1d2b8672fd801fe55cdfea34a45e7ec8 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -706,7 +706,7 @@ pub const ExecutableOptions = struct { single_threaded: ?bool = null, pic: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, omit_frame_pointer: ?bool = null, sanitize_thread: ?bool = null, error_tracing: ?bool = null, @@ -762,7 +762,7 @@ pub const ObjectOptions = struct { single_threaded: ?bool = null, pic: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, omit_frame_pointer: ?bool = null, sanitize_thread: ?bool = null, error_tracing: ?bool = null, @@ -810,7 +810,7 @@ pub const SharedLibraryOptions = struct { single_threaded: ?bool = null, pic: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, omit_frame_pointer: ?bool = null, sanitize_thread: ?bool = null, error_tracing: ?bool = null, @@ -867,7 +867,7 @@ pub const StaticLibraryOptions = struct { single_threaded: ?bool = null, pic: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, omit_frame_pointer: ?bool = null, sanitize_thread: ?bool = null, error_tracing: ?bool = null, @@ -919,7 +919,7 @@ pub const TestOptions = struct { single_threaded: ?bool = null, pic: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, omit_frame_pointer: ?bool = null, sanitize_thread: ?bool = null, error_tracing: ?bool = null, diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 347695a4c038a70640dad9ea42ba78895ce8d75e..0e421280f0958ca4bf7fa2fcc7d712f37869923a 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -22,7 +22,7 @@ frameworks: std.StringArrayHashMapUnmanaged(LinkFrameworkOptions), link_objects: std.ArrayListUnmanaged(LinkObject), strip: ?bool, -unwind_tables: ?bool, +unwind_tables: ?std.builtin.UnwindTables, single_threaded: ?bool, stack_protector: ?bool, stack_check: ?bool, @@ -218,7 +218,7 @@ pub const CreateOptions = struct { link_libcpp: ?bool = null, single_threaded: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, dwarf_format: ?std.dwarf.Format = null, code_model: std.builtin.CodeModel = .default, stack_protector: ?bool = null, @@ -675,7 +675,6 @@ pub fn appendZigProcessFlags( const b = m.owner; try addFlag(zig_args, m.strip, "-fstrip", "-fno-strip"); - try addFlag(zig_args, m.unwind_tables, "-funwind-tables", "-fno-unwind-tables"); try addFlag(zig_args, m.single_threaded, "-fsingle-threaded", "-fno-single-threaded"); try addFlag(zig_args, m.stack_check, "-fstack-check", "-fno-stack-check"); try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector"); @@ -695,6 +694,14 @@ pub fn appendZigProcessFlags( }); } + if (m.unwind_tables) |unwind_tables| { + try zig_args.append(switch (unwind_tables) { + .none => "-fno-unwind-tables", + .sync => "-funwind-tables", + .@"async" => "-fasync-unwind-tables", + }); + } + try zig_args.ensureUnusedCapacity(1); if (m.optimize) |optimize| switch (optimize) { .Debug => zig_args.appendAssumeCapacity("-ODebug"), diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 5ddde66a0a0a3c89a09b7278e2c44a32d3d8369e..eda7f0ff4f5e66e43a0319461968e720ce7b8a1e 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -804,6 +804,14 @@ pub const LinkMode = enum { dynamic, }; +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const UnwindTables = enum { + none, + sync, + @"async", +}; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const WasiExecModel = enum { diff --git a/src/Builtin.zig b/src/Builtin.zig index 8dc5b31c163967d473b8613eadf34497ba581c7f..1782527f699b511f88d4621e8032b7fd4c87170a 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -2,6 +2,7 @@ target: std.Target, zig_backend: std.builtin.CompilerBackend, output_mode: std.builtin.OutputMode, link_mode: std.builtin.LinkMode, +unwind_tables: std.builtin.UnwindTables, is_test: bool, single_threaded: bool, link_libc: bool, @@ -40,6 +41,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { \\ \\pub const output_mode: std.builtin.OutputMode = .{p_}; \\pub const link_mode: std.builtin.LinkMode = .{p_}; + \\pub const unwind_tables: std.builtin.UnwindTables = .{p_}; \\pub const is_test = {}; \\pub const single_threaded = {}; \\pub const abi: std.Target.Abi = .{p_}; @@ -53,6 +55,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { std.zig.fmtId(@tagName(zig_backend)), std.zig.fmtId(@tagName(opts.output_mode)), std.zig.fmtId(@tagName(opts.link_mode)), + std.zig.fmtId(@tagName(opts.unwind_tables)), opts.is_test, opts.single_threaded, std.zig.fmtId(@tagName(target.abi)), diff --git a/src/Compilation.zig b/src/Compilation.zig index c198b5af8269e8fdc0676dc0c740b3052221eb4b..16d3589b5dd467527740ba624d5ff80e544ba53c 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1261,12 +1261,15 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil // The "any" values provided by resolved config only account for // explicitly-provided settings. We now make them additionally account // for default setting resolution. - const any_unwind_tables = options.config.any_unwind_tables or options.root_mod.unwind_tables; + const any_unwind_tables = switch (options.config.any_unwind_tables) { + .none => options.root_mod.unwind_tables, + .sync, .@"async" => |uwt| uwt, + }; const any_non_single_threaded = options.config.any_non_single_threaded or !options.root_mod.single_threaded; const any_sanitize_thread = options.config.any_sanitize_thread or options.root_mod.sanitize_thread; const any_fuzz = options.config.any_fuzz or options.root_mod.fuzz; - const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables; + const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables != .none; const build_id = options.build_id orelse .none; const link_libc = options.config.link_libc; @@ -1354,6 +1357,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil cache.hash.add(options.config.pie); cache.hash.add(options.config.lto); cache.hash.add(options.config.link_mode); + cache.hash.add(options.config.any_unwind_tables); cache.hash.add(options.function_sections); cache.hash.add(options.data_sections); cache.hash.add(link_libc); @@ -5538,10 +5542,17 @@ pub fn addCCArgs( try argv.append("-Werror=date-time"); } - if (mod.unwind_tables) { - try argv.append("-funwind-tables"); - } else { - try argv.append("-fno-unwind-tables"); + switch (mod.unwind_tables) { + .none => { + try argv.append("-fno-unwind-tables"); + try argv.append("-fno-asynchronous-unwind-tables"); + }, + .sync => { + // Need to override Clang's convoluted default logic. + try argv.append("-fno-asynchronous-unwind-tables"); + try argv.append("-funwind-tables"); + }, + .@"async" => try argv.append("-fasynchronous-unwind-tables"), } }, .shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig, .res, .manifest => {}, @@ -6273,6 +6284,7 @@ pub const CrtFileOptions = struct { function_sections: ?bool = null, data_sections: ?bool = null, omit_frame_pointer: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, pic: ?bool = null, no_builtin: ?bool = null, }; @@ -6334,7 +6346,8 @@ pub fn build_crt_file( // Some libcs (e.g. musl) are opinionated about -fomit-frame-pointer. .omit_frame_pointer = options.omit_frame_pointer orelse comp.root_mod.omit_frame_pointer, .valgrind = false, - .unwind_tables = false, + // Some libcs (e.g. MinGW) are opinionated about -funwind-tables. + .unwind_tables = options.unwind_tables orelse .none, // Some CRT objects (e.g. musl's rcrt1.o and Scrt1.o) are opinionated about PIC. .pic = options.pic orelse comp.root_mod.pic, .optimize_mode = comp.compilerRtOptMode(), diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 4458d474bbf03d4aeb7c1aa02352f5f0bd2ac8e8..baaa6c9f4741bddd893c60327fc0c6edd5eda037 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -12,13 +12,14 @@ link_libunwind: bool, /// True if and only if the c_source_files field will have nonzero length when /// calling Compilation.create. any_c_source_files: bool, -/// This is true if any Module has unwind_tables set explicitly to true. Until -/// Compilation.create is called, it is possible for this to be false while in -/// fact all Module instances have unwind_tables=true due to the default -/// being unwind_tables=true. After Compilation.create is called this will -/// also take into account the default setting, making this value true if and -/// only if any Module has unwind_tables set to true. -any_unwind_tables: bool, +/// This is not `.none` if any `Module` has `unwind_tables` set explicitly to a +/// value other than `.none`. Until `Compilation.create()` is called, it is +/// possible for this to be `.none` while in fact all `Module` instances have +/// `unwind_tables != .none` due to the default. After `Compilation.create()` is +/// called, this will also take into account the default setting, making this +/// value `.sync` or `.@"async"` if and only if any `Module` has +/// `unwind_tables != .none`. +any_unwind_tables: std.builtin.UnwindTables, /// This is true if any Module has single_threaded set explicitly to false. Until /// Compilation.create is called, it is possible for this to be false while in /// fact all Module instances have single_threaded=false due to the default @@ -85,7 +86,7 @@ pub const Options = struct { any_non_single_threaded: bool = false, any_sanitize_thread: bool = false, any_fuzz: bool = false, - any_unwind_tables: bool = false, + any_unwind_tables: std.builtin.UnwindTables = .none, any_dyn_libs: bool = false, any_c_source_files: bool = false, any_non_stripped: bool = false, @@ -356,8 +357,11 @@ pub fn resolve(options: Options) ResolveError!Config { break :b false; }; - const any_unwind_tables = options.any_unwind_tables or - link_libunwind or target_util.needUnwindTables(target); + const any_unwind_tables = b: { + if (options.any_unwind_tables != .none) break :b options.any_unwind_tables; + + break :b target_util.needUnwindTables(target, link_libunwind, options.any_sanitize_thread); + }; const link_mode = b: { const explicitly_exe_or_dyn_lib = switch (options.output_mode) { diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 781a8e50c25dcdf44fd6b4b900b94c18a499de4b..bfcef038edb757e2f757fe3d8b1dd2c18e80b73f 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -27,7 +27,7 @@ red_zone: bool, sanitize_c: bool, sanitize_thread: bool, fuzz: bool, -unwind_tables: bool, +unwind_tables: std.builtin.UnwindTables, cc_argv: []const []const u8, /// (SPIR-V) whether to generate a structured control flow graph or not structured_cfg: bool, @@ -91,7 +91,7 @@ pub const CreateOptions = struct { /// other number means stack protection with that buffer size. stack_protector: ?u32 = null, red_zone: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, sanitize_c: ?bool = null, sanitize_thread: ?bool = null, fuzz: ?bool = null, @@ -112,7 +112,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { if (options.inherited.sanitize_thread == true) assert(options.global.any_sanitize_thread); if (options.inherited.fuzz == true) assert(options.global.any_fuzz); if (options.inherited.single_threaded == false) assert(options.global.any_non_single_threaded); - if (options.inherited.unwind_tables == true) assert(options.global.any_unwind_tables); + if (options.inherited.unwind_tables) |uwt| if (uwt != .none) assert(options.global.any_unwind_tables != .none); if (options.inherited.error_tracing == true) assert(options.global.any_error_tracing); const resolved_target = options.inherited.resolved_target orelse options.parent.?.resolved_target; @@ -382,6 +382,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .zig_backend = zig_backend, .output_mode = options.global.output_mode, .link_mode = options.global.link_mode, + .unwind_tables = options.global.any_unwind_tables, .is_test = options.global.is_test, .single_threaded = single_threaded, .link_libc = options.global.link_libc, diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index 9ced7e9ebe2137df5d8d1150c79f44f7e368d5c8..88cf41d0d4ff0b145f8ea05db79da08429c9642b 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -2757,7 +2757,14 @@ flagpd1("fast"), flagpd1("fastcp"), flagpd1("fastf"), flagpd1("fasync-exceptions"), -flagpd1("fasynchronous-unwind-tables"), +.{ + .name = "fasynchronous-unwind-tables", + .syntax = .flag, + .zig_equivalent = .asynchronous_unwind_tables, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fauto-import"), flagpd1("fauto-profile"), flagpd1("fauto-profile-accurate"), @@ -3247,7 +3254,14 @@ flagpd1("fno-assume-sane-operator-new"), flagpd1("fno-assume-unique-vtables"), flagpd1("fno-assumptions"), flagpd1("fno-async-exceptions"), -flagpd1("fno-asynchronous-unwind-tables"), +.{ + .name = "fno-asynchronous-unwind-tables", + .syntax = .flag, + .zig_equivalent = .no_asynchronous_unwind_tables, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fno-auto-import"), flagpd1("fno-auto-profile"), flagpd1("fno-auto-profile-accurate"), diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ff1e6798988000b8ae586f1f2a489897a611a79b..b94ea0799573879fdaa43b1e139e83d5acf14366 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3141,8 +3141,11 @@ pub const Object = struct { } }, &o.builder); } try attributes.addFnAttr(.nounwind, &o.builder); - if (owner_mod.unwind_tables) { - try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder); + if (owner_mod.unwind_tables != .none) { + try attributes.addFnAttr( + .{ .uwtable = if (owner_mod.unwind_tables == .@"async") .@"async" else .sync }, + &o.builder, + ); } if (owner_mod.no_builtin) { // The intent here is for compiler-rt and libc functions to not generate diff --git a/src/libcxx.zig b/src/libcxx.zig index 39fd999112d04f97d98230848e3681b6450b52d3..6386d493a608cd88e97a2d177764b00a8f79ca44 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -397,7 +397,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); - const unwind_tables = true; const config = Compilation.Config.resolve(.{ .output_mode = output_mode, @@ -409,7 +408,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .root_optimize_mode = optimize_mode, .root_strip = strip, .link_libc = true, - .any_unwind_tables = unwind_tables, .lto = comp.config.lto, .any_sanitize_thread = comp.config.any_sanitize_thread, }) catch |err| { @@ -440,7 +438,12 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .valgrind = false, .optimize_mode = optimize_mode, .structured_cfg = comp.root_mod.structured_cfg, - .unwind_tables = unwind_tables, + // See the `-fno-exceptions` logic for WASI. + // The old 32-bit x86 variant of SEH doesn't use tables. + .unwind_tables = if (target.os.tag == .wasi or (target.cpu.arch == .x86 and target.os.tag == .windows)) + .none + else + .@"async", .pic = comp.root_mod.pic, }, .global = config, diff --git a/src/libunwind.zig b/src/libunwind.zig index 1e101da229f0167afe69cbbbbbebd2fc14a6fcc4..4b3583e1cde4a612dc3118f60d42dba764bf6f23 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -65,7 +65,8 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .sanitize_c = false, .sanitize_thread = false, // necessary so that libunwind can unwind through its own stack frames - .unwind_tables = true, + // The old 32-bit x86 variant of SEH doesn't use tables. + .unwind_tables = if (target.cpu.arch == .x86 and target.os.tag == .windows) .none else .@"async", .pic = if (target_util.supports_fpic(target)) true else null, .optimize_mode = comp.compilerRtOptMode(), }, diff --git a/src/main.zig b/src/main.zig index 23c4d7507e450fab2de8de491d6384ff08b9d2fa..1f8bd8d06541b767a6b4150b32e3e0cab93673c1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -510,6 +510,7 @@ const usage_build_generic = \\ -ffuzz Enable fuzz testing instrumentation \\ -fno-fuzz Disable fuzz testing instrumentation \\ -funwind-tables Always produce unwind table entries for all functions + \\ -fasync-unwind-tables Always produce asynchronous unwind table entries for all functions \\ -fno-unwind-tables Never produce unwind table entries \\ -ferror-tracing Enable error tracing in ReleaseFast mode \\ -fno-error-tracing Disable error tracing in Debug and ReleaseSafe mode @@ -1385,9 +1386,11 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-lto")) { create_module.opts.lto = false; } else if (mem.eql(u8, arg, "-funwind-tables")) { - mod_opts.unwind_tables = true; + mod_opts.unwind_tables = .sync; + } else if (mem.eql(u8, arg, "-fasync-unwind-tables")) { + mod_opts.unwind_tables = .@"async"; } else if (mem.eql(u8, arg, "-fno-unwind-tables")) { - mod_opts.unwind_tables = false; + mod_opts.unwind_tables = .none; } else if (mem.eql(u8, arg, "-fstack-check")) { mod_opts.stack_check = true; } else if (mem.eql(u8, arg, "-fno-stack-check")) { @@ -1973,8 +1976,27 @@ fn buildOutputType( } }, .no_stack_protector => mod_opts.stack_protector = 0, - .unwind_tables => mod_opts.unwind_tables = true, - .no_unwind_tables => mod_opts.unwind_tables = false, + // The way these unwind table options are processed in GCC and Clang is crazy + // convoluted, and we also don't know the target triple here, so this is all + // best-effort. + .unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) { + .none => { + mod_opts.unwind_tables = .sync; + }, + .sync, .@"async" => {}, + } else { + mod_opts.unwind_tables = .sync; + }, + .no_unwind_tables => mod_opts.unwind_tables = .none, + .asynchronous_unwind_tables => mod_opts.unwind_tables = .@"async", + .no_asynchronous_unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) { + .none, .sync => {}, + .@"async" => { + mod_opts.unwind_tables = .sync; + }, + } else { + mod_opts.unwind_tables = .sync; + }, .nostdlib => { create_module.opts.ensure_libc_on_non_freestanding = false; create_module.opts.ensure_libcpp_on_non_freestanding = false; @@ -2788,8 +2810,15 @@ fn buildOutputType( create_module.opts.any_sanitize_thread = true; if (mod_opts.fuzz == true) create_module.opts.any_fuzz = true; - if (mod_opts.unwind_tables == true) - create_module.opts.any_unwind_tables = true; + if (mod_opts.unwind_tables) |uwt| switch (uwt) { + .none => {}, + .sync => if (create_module.opts.any_unwind_tables == .none) { + create_module.opts.any_unwind_tables = .sync; + }, + .@"async" => { + create_module.opts.any_unwind_tables = .@"async"; + }, + }; if (mod_opts.strip == false) create_module.opts.any_non_stripped = true; if (mod_opts.error_tracing == true) @@ -5713,6 +5742,8 @@ pub const ClangArgIterator = struct { no_lto, unwind_tables, no_unwind_tables, + asynchronous_unwind_tables, + no_asynchronous_unwind_tables, nostdlib, nostdlib_cpp, shared, @@ -7435,8 +7466,15 @@ fn handleModArg( create_module.opts.any_sanitize_thread = true; if (mod_opts.fuzz == true) create_module.opts.any_fuzz = true; - if (mod_opts.unwind_tables == true) - create_module.opts.any_unwind_tables = true; + if (mod_opts.unwind_tables) |uwt| switch (uwt) { + .none => {}, + .sync => if (create_module.opts.any_unwind_tables == .none) { + create_module.opts.any_unwind_tables = .sync; + }, + .@"async" => { + create_module.opts.any_unwind_tables = .@"async"; + }, + }; if (mod_opts.strip == false) create_module.opts.any_non_stripped = true; if (mod_opts.error_tracing == true) diff --git a/src/mingw.zig b/src/mingw.zig index cdee9acb070b32188863126c4c6921636d853f0c..8473a7a93b235c1073eb5c6955b964352a641943 100644 --- a/src/mingw.zig +++ b/src/mingw.zig @@ -24,6 +24,10 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); + const target = comp.getTarget(); + + // The old 32-bit x86 variant of SEH doesn't use tables. + const unwind_tables: std.builtin.UnwindTables = if (target.cpu.arch != .x86) .@"async" else .none; switch (crt_file) { .crt2_o => { @@ -41,7 +45,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre .owner = undefined, }, }; - return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files, .{}); + return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files, .{ + .unwind_tables = unwind_tables, + }); }, .dllcrt2_o => { @@ -56,7 +62,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre .owner = undefined, }, }; - return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{}); + return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{ + .unwind_tables = unwind_tables, + }); }, .mingw32_lib => { @@ -73,7 +81,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre .owner = undefined, }); } - const target = comp.getTarget(); if (target.cpu.arch == .x86 or target.cpu.arch == .x86_64) { for (mingw32_x86_src) |dep| { try c_source_files.append(.{ @@ -118,7 +125,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre } else { @panic("unsupported arch"); } - return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items, .{}); + return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items, .{ + .unwind_tables = unwind_tables, + }); }, } } diff --git a/src/target.zig b/src/target.zig index a1c9a1972482719f406a11a3979d6ee81fa9db16..37f2cd50da50566ff454dac72d6c7fda1763595a 100644 --- a/src/target.zig +++ b/src/target.zig @@ -4,6 +4,7 @@ const assert = std.debug.assert; const Type = @import("Type.zig"); const AddressSpace = std.builtin.AddressSpace; const Alignment = @import("InternPool.zig").Alignment; +const Compilation = @import("Compilation.zig"); const Feature = @import("Zcu.zig").Feature; pub const default_stack_protector_buffer_size = 4; @@ -408,8 +409,16 @@ pub fn clangSupportsNoImplicitFloatArg(target: std.Target) bool { }; } -pub fn needUnwindTables(target: std.Target) bool { - return target.os.tag == .windows or target.isDarwin() or std.debug.Dwarf.abi.supportsUnwinding(target); +pub fn needUnwindTables(target: std.Target, libunwind: bool, libtsan: bool) std.builtin.UnwindTables { + if (target.os.tag == .windows) { + // The old 32-bit x86 variant of SEH doesn't use tables. + return if (target.cpu.arch != .x86) .@"async" else .none; + } + if (target.os.tag.isDarwin()) return .@"async"; + if (libunwind) return .@"async"; + if (libtsan) return .@"async"; + if (std.debug.Dwarf.abi.supportsUnwinding(target)) return .@"async"; + return .none; } pub fn defaultAddressSpace( diff --git a/test/standalone/stack_iterator/build.zig b/test/standalone/stack_iterator/build.zig index ac9a6769304c0c35b989e1bdc80210e253fff5e9..38f66edd9f606c3a80a367b0d41e959b1808dcf4 100644 --- a/test/standalone/stack_iterator/build.zig +++ b/test/standalone/stack_iterator/build.zig @@ -23,7 +23,7 @@ pub fn build(b: *std.Build) void { .root_source_file = b.path("unwind.zig"), .target = target, .optimize = optimize, - .unwind_tables = if (target.result.isDarwin()) true else null, + .unwind_tables = if (target.result.isDarwin()) .@"async" else null, .omit_frame_pointer = false, }); @@ -46,7 +46,7 @@ pub fn build(b: *std.Build) void { .root_source_file = b.path("unwind.zig"), .target = target, .optimize = optimize, - .unwind_tables = true, + .unwind_tables = .@"async", .omit_frame_pointer = true, }); @@ -85,7 +85,7 @@ pub fn build(b: *std.Build) void { .root_source_file = b.path("shared_lib_unwind.zig"), .target = target, .optimize = optimize, - .unwind_tables = if (target.result.isDarwin()) true else null, + .unwind_tables = if (target.result.isDarwin()) .@"async" else null, .omit_frame_pointer = true, }); diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index 637c9a5eaff6d50f5177ea234e8a18746febab3f..9cc0ad90cd71cad892ffb64036c591c57b1ee1d4 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -110,6 +110,14 @@ const known_options = [_]KnownOpt{ .name = "fno-unwind-tables", .ident = "no_unwind_tables", }, + .{ + .name = "fasynchronous-unwind-tables", + .ident = "asynchronous_unwind_tables", + }, + .{ + .name = "fno-asynchronous-unwind-tables", + .ident = "no_asynchronous_unwind_tables", + }, .{ .name = "nolibc", .ident = "nostdlib", -- 2.54.0