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.
This commit is contained in:
Alex Rønne Petersen 2024-11-13 06:04:04 +01:00
parent dcbb811d72
commit 9986e6b623
No known key found for this signature in database
16 changed files with 169 additions and 53 deletions

View File

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

View File

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

View File

@ -803,6 +803,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 {

View File

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

View File

@ -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);
@ -5539,10 +5543,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 => {},
@ -6269,6 +6280,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,
};
@ -6330,7 +6342,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(),

View File

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

View File

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

View File

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

View File

@ -3237,8 +3237,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

View File

@ -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,8 @@ 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.
.unwind_tables = if (target.os.tag == .wasi) .none else .@"async",
.pic = comp.root_mod.pic,
},
.global = config,

View File

@ -65,7 +65,7 @@ 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,
.unwind_tables = .@"async",
.pic = if (target_util.supports_fpic(target)) true else null,
.optimize_mode = comp.compilerRtOptMode(),
},

View File

@ -509,6 +509,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
@ -1384,9 +1385,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")) {
@ -1972,8 +1975,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;
@ -2787,8 +2809,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)
@ -5711,6 +5740,8 @@ pub const ClangArgIterator = struct {
no_lto,
unwind_tables,
no_unwind_tables,
asynchronous_unwind_tables,
no_asynchronous_unwind_tables,
nostdlib,
nostdlib_cpp,
shared,
@ -7420,8 +7451,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)

View File

@ -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,
});
},
}
}

View File

@ -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;
@ -396,8 +397,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(

View File

@ -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,
});

View File

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