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
This commit is contained in:
Andrew Kelley
2021-06-10 11:25:33 -07:00
parent e3a74697f0
commit 264969a8c3
10 changed files with 82 additions and 22 deletions

View File

@@ -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,
@@ -659,6 +660,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,
@@ -815,8 +817,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;
@@ -835,7 +849,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
@@ -894,15 +908,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;
@@ -1072,6 +1077,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);
@@ -1303,7 +1309,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,
@@ -1366,6 +1372,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,
@@ -2963,6 +2970,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 => {
@@ -3927,6 +3940,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,

View File

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

View File

@@ -263,22 +263,26 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
}
const usage_build_generic =
\\Usage: zig build-exe <options> [files]
\\ zig build-lib <options> [files]
\\ zig build-obj <options> [files]
\\ zig test <options> [files]
\\ zig run <options> [file] [-- [args]]
\\Usage: zig build-exe <options> [files]
\\ zig build-lib <options> [files]
\\ zig build-obj <options> [files]
\\ zig test <options> [files]
\\ zig run <options> [file] [-- [args]]
\\ zig translate-c <options> [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)
@@ -341,6 +345,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
@@ -568,6 +574,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;
@@ -920,6 +927,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")) {
@@ -1151,6 +1162,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 => {
@@ -1893,6 +1906,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,
@@ -3294,6 +3308,8 @@ pub const ClangArgIterator = struct {
no_pie,
lto,
no_lto,
unwind_tables,
no_unwind_tables,
nostdlib,
nostdlib_cpp,
shared,

View File

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

View File

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

View File

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

View File

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

View File

@@ -182,6 +182,7 @@ struct ZigStage1 {
bool pic;
bool pie;
bool lto;
bool unwind_tables;
bool link_libc;
bool link_libcpp;
bool strip;

View File

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

View File

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