From b6277a4b1c2be27701d594bc1465ac72fc226260 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 10 Jun 2021 11:25:33 -0700 Subject: [PATCH] better awareness of unwind tables * stage1 backend allows configuring the uwtables function attr via a flag rather than its own logic. * stage2 defaults to enabling uwtable attr when linking libunwind, or always on windows * stage2 makes link_eh_frame_hdr true automatically if uwtable attr is set to be on for zig functions * CLI: add -funwind-tables and -fno-unwind-tables to allow the user to override the defaults. * hook it up to `zig cc` closes #9046 --- src/Compilation.zig | 38 +++++++++++++++++++++++----------- src/clang_options_data.zig | 18 ++++++++++++++-- src/main.zig | 30 ++++++++++++++++++++------- src/stage1.zig | 1 + src/stage1/all_types.hpp | 1 + src/stage1/codegen.cpp | 2 +- src/stage1/stage1.cpp | 1 + src/stage1/stage1.h | 1 + src/target.zig | 4 ++++ tools/update_clang_options.zig | 8 +++++++ 10 files changed, 82 insertions(+), 22 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 3295f9fc3c..00c5937394 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -81,6 +81,7 @@ verbose_llvm_cpu_features: bool, disable_c_depfile: bool, time_report: bool, stack_report: bool, +unwind_tables: bool, c_source_files: []const CSourceFile, clang_argv: []const []const u8, @@ -665,6 +666,7 @@ pub const InitOptions = struct { want_tsan: ?bool = null, want_compiler_rt: ?bool = null, want_lto: ?bool = null, + want_unwind_tables: ?bool = null, use_llvm: ?bool = null, use_lld: ?bool = null, use_clang: ?bool = null, @@ -823,8 +825,20 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { return error.MachineCodeModelNotSupported; } + const tsan = options.want_tsan orelse false; + // TSAN is implemented in C++ so it requires linking libc++. + const link_libcpp = options.link_libcpp or tsan; + const link_libc = link_libcpp or options.link_libc or + target_util.osRequiresLibC(options.target); + + const link_libunwind = options.link_libunwind or + (link_libcpp and target_util.libcNeedsLibUnwind(options.target)); + const unwind_tables = options.want_unwind_tables orelse + (link_libunwind or target_util.needUnwindTables(options.target)); + const link_eh_frame_hdr = options.link_eh_frame_hdr or unwind_tables; + // Make a decision on whether to use LLD or our own linker. - const use_lld = if (options.use_lld) |explicit| explicit else blk: { + const use_lld = options.use_lld orelse blk: { if (!build_options.have_llvm) break :blk false; @@ -843,7 +857,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { options.frameworks.len != 0 or options.system_libs.len != 0 or options.link_libc or options.link_libcpp or - options.link_eh_frame_hdr or + link_eh_frame_hdr or options.link_emit_relocs or options.output_mode == .Lib or options.lld_argv.len != 0 or @@ -902,15 +916,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { } }; - const tsan = options.want_tsan orelse false; - // TSAN is implemented in C++ so it requires linking libc++. - const link_libcpp = options.link_libcpp or tsan; - const link_libc = link_libcpp or options.link_libc or - target_util.osRequiresLibC(options.target); - - const link_libunwind = options.link_libunwind or - (link_libcpp and target_util.libcNeedsLibUnwind(options.target)); - const must_dynamic_link = dl: { if (target_util.cannotDynamicLink(options.target)) break :dl false; @@ -1080,6 +1085,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { cache.hash.add(pic); cache.hash.add(pie); cache.hash.add(lto); + cache.hash.add(unwind_tables); cache.hash.add(tsan); cache.hash.add(stack_check); cache.hash.add(red_zone); @@ -1312,7 +1318,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .linker_script = options.linker_script, .version_script = options.version_script, .gc_sections = options.linker_gc_sections, - .eh_frame_hdr = options.link_eh_frame_hdr, + .eh_frame_hdr = link_eh_frame_hdr, .emit_relocs = options.link_emit_relocs, .rdynamic = options.rdynamic, .extra_lld_args = options.lld_argv, @@ -1376,6 +1382,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .color = options.color, .time_report = options.time_report, .stack_report = options.stack_report, + .unwind_tables = unwind_tables, .test_filter = options.test_filter, .test_name_prefix = options.test_name_prefix, .test_evented_io = options.test_evented_io, @@ -2983,6 +2990,12 @@ pub fn addCCArgs( if (target_util.supports_fpic(target) and comp.bin_file.options.pic) { try argv.append("-fPIC"); } + + if (comp.unwind_tables) { + try argv.append("-funwind-tables"); + } else { + try argv.append("-fno-unwind-tables"); + } }, .shared_library, .ll, .bc, .unknown, .static_library, .object, .zig => {}, .assembly => { @@ -3948,6 +3961,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node .pic = comp.bin_file.options.pic, .pie = comp.bin_file.options.pie, .lto = comp.bin_file.options.lto, + .unwind_tables = comp.unwind_tables, .link_libc = comp.bin_file.options.link_libc, .link_libcpp = comp.bin_file.options.link_libcpp, .strip = comp.bin_file.options.strip, diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index be4e5c13cb..daaa8c4310 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -3151,7 +3151,14 @@ flagpd1("fno-unsafe-loop-optimizations"), flagpd1("fno-unsafe-math-optimizations"), flagpd1("fno-unsigned-char"), flagpd1("fno-unswitch-loops"), -flagpd1("fno-unwind-tables"), +.{ + .name = "fno-unwind-tables", + .syntax = .flag, + .zig_equivalent = .no_unwind_tables, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fno-use-cxa-atexit"), flagpd1("fno-use-init-array"), flagpd1("fno-use-line-directives"), @@ -3410,7 +3417,14 @@ flagpd1("funsafe-math-optimizations"), flagpd1("funsigned-bitfields"), flagpd1("funsigned-char"), flagpd1("funswitch-loops"), -flagpd1("funwind-tables"), +.{ + .name = "funwind-tables", + .syntax = .flag, + .zig_equivalent = .unwind_tables, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fuse-ctor-homing"), flagpd1("fuse-cxa-atexit"), flagpd1("fuse-init-array"), diff --git a/src/main.zig b/src/main.zig index 631d4ef460..081b9ac335 100644 --- a/src/main.zig +++ b/src/main.zig @@ -264,22 +264,26 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v } const usage_build_generic = - \\Usage: zig build-exe [files] - \\ zig build-lib [files] - \\ zig build-obj [files] - \\ zig test [files] - \\ zig run [file] [-- [args]] + \\Usage: zig build-exe [files] + \\ zig build-lib [files] + \\ zig build-obj [files] + \\ zig test [files] + \\ zig run [file] [-- [args]] + \\ zig translate-c [file] \\ \\Supported file types: \\ .zig Zig source code \\ .o ELF object file - \\ .o MACH-O (macOS) object file + \\ .o Mach-O (macOS) object file + \\ .o WebAssembly object file \\ .obj COFF (Windows) object file \\ .lib COFF (Windows) static library \\ .a ELF static library + \\ .a Mach-O (macOS) static library + \\ .a WebAssembly static library \\ .so ELF shared object (dynamic link) \\ .dll Windows Dynamic Link Library - \\ .dylib MACH-O (macOS) dynamic library + \\ .dylib Mach-O (macOS) dynamic library \\ .tbd (macOS) text-based dylib definition \\ .s Target-specific assembly source code \\ .S Assembly with C preprocessor (requires LLVM extensions) @@ -342,6 +346,8 @@ const usage_build_generic = \\ -fno-sanitize-thread Disable Thread Sanitizer \\ -fdll-export-fns Mark exported functions as DLL exports (Windows) \\ -fno-dll-export-fns Force-disable marking exported functions as DLL exports + \\ -funwind-tables Always produce unwind table entries for all functions + \\ -fno-unwind-tables Never produce unwind table entries \\ -fLLVM Force using LLVM as the codegen backend \\ -fno-LLVM Prevent using LLVM as a codegen backend \\ -fClang Force using Clang as the C/C++ compilation backend @@ -569,6 +575,7 @@ fn buildOutputType( var want_pic: ?bool = null; var want_pie: ?bool = null; var want_lto: ?bool = null; + var want_unwind_tables: ?bool = null; var want_sanitize_c: ?bool = null; var want_stack_check: ?bool = null; var want_red_zone: ?bool = null; @@ -925,6 +932,10 @@ fn buildOutputType( want_lto = true; } else if (mem.eql(u8, arg, "-fno-lto")) { want_lto = false; + } else if (mem.eql(u8, arg, "-funwind-tables")) { + want_unwind_tables = true; + } else if (mem.eql(u8, arg, "-fno-unwind-tables")) { + want_unwind_tables = false; } else if (mem.eql(u8, arg, "-fstack-check")) { want_stack_check = true; } else if (mem.eql(u8, arg, "-fno-stack-check")) { @@ -1156,6 +1167,8 @@ fn buildOutputType( .no_lto => want_lto = false, .red_zone => want_red_zone = true, .no_red_zone => want_red_zone = false, + .unwind_tables => want_unwind_tables = true, + .no_unwind_tables => want_unwind_tables = false, .nostdlib => ensure_libc_on_non_freestanding = false, .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false, .shared => { @@ -1913,6 +1926,7 @@ fn buildOutputType( .want_pic = want_pic, .want_pie = want_pie, .want_lto = want_lto, + .want_unwind_tables = want_unwind_tables, .want_sanitize_c = want_sanitize_c, .want_stack_check = want_stack_check, .want_red_zone = want_red_zone, @@ -3315,6 +3329,8 @@ pub const ClangArgIterator = struct { no_pie, lto, no_lto, + unwind_tables, + no_unwind_tables, nostdlib, nostdlib_cpp, shared, diff --git a/src/stage1.zig b/src/stage1.zig index 2a304816b6..fc7b86e727 100644 --- a/src/stage1.zig +++ b/src/stage1.zig @@ -110,6 +110,7 @@ pub const Module = extern struct { pic: bool, pie: bool, lto: bool, + unwind_tables: bool, link_libc: bool, link_libcpp: bool, strip: bool, diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index b07275eca7..949945dea4 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -2144,6 +2144,7 @@ struct CodeGen { bool have_pic; bool have_pie; bool have_lto; + bool unwind_tables; bool link_mode_dynamic; bool dll_export_fns; bool have_stack_probing; diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 5face0b4b6..4aa02680a2 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -211,7 +211,7 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) { } static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { - if (g->zig_target->os == OsWindows) { + if (g->unwind_tables) { addLLVMFnAttr(fn_val, "uwtable"); } } diff --git a/src/stage1/stage1.cpp b/src/stage1/stage1.cpp index 5193c4b436..e7c316f385 100644 --- a/src/stage1/stage1.cpp +++ b/src/stage1/stage1.cpp @@ -91,6 +91,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) { g->have_pic = stage1->pic; g->have_pie = stage1->pie; g->have_lto = stage1->lto; + g->unwind_tables = stage1->unwind_tables; g->have_stack_probing = stage1->enable_stack_probing; g->red_zone = stage1->red_zone; g->is_single_threaded = stage1->is_single_threaded; diff --git a/src/stage1/stage1.h b/src/stage1/stage1.h index c0b04b80cc..ab4d103230 100644 --- a/src/stage1/stage1.h +++ b/src/stage1/stage1.h @@ -182,6 +182,7 @@ struct ZigStage1 { bool pic; bool pie; bool lto; + bool unwind_tables; bool link_libc; bool link_libcpp; bool strip; diff --git a/src/target.zig b/src/target.zig index 59be06f296..d7c39d62a0 100644 --- a/src/target.zig +++ b/src/target.zig @@ -404,3 +404,7 @@ pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool { else => false, }; } + +pub fn needUnwindTables(target: std.Target) bool { + return target.os.tag == .windows; +} diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index ad2a9ffe53..4a54955a0d 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -70,6 +70,14 @@ const known_options = [_]KnownOpt{ .name = "fno-lto", .ident = "no_lto", }, + .{ + .name = "funwind-tables", + .ident = "unwind_tables", + }, + .{ + .name = "fno-unwind-tables", + .ident = "no_unwind_tables", + }, .{ .name = "nolibc", .ident = "nostdlib",