diff --git a/lib/std/build.zig b/lib/std/build.zig index 5fd64cad0b..381488d800 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1332,6 +1332,8 @@ pub const LibExeObjStep = struct { /// Position Independent Executable pie: ?bool = null, + red_zone: ?bool = null, + subsystem: ?builtin.SubSystem = null, /// Overrides the default stack size @@ -2260,6 +2262,13 @@ pub const LibExeObjStep = struct { if (self.disable_stack_probing) { try zig_args.append("-fno-stack-check"); } + if (self.red_zone) |red_zone| { + if (red_zone) { + try zig_args.append("-mred-zone"); + } else { + try zig_args.append("-mno-red-zone"); + } + } if (self.disable_sanitize_c) { try zig_args.append("-fno-sanitize-c"); } diff --git a/src/Compilation.zig b/src/Compilation.zig index b017dde8c8..0efad3362d 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -392,6 +392,7 @@ pub const InitOptions = struct { want_pie: ?bool = null, want_sanitize_c: ?bool = null, want_stack_check: ?bool = null, + want_red_zone: ?bool = null, want_valgrind: ?bool = null, want_tsan: ?bool = null, want_compiler_rt: ?bool = null, @@ -743,6 +744,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { } else null; const strip = options.strip or !target_util.hasDebugInfo(options.target); + const red_zone = options.want_red_zone orelse target_util.hasRedZone(options.target); // We put everything into the cache hash that *cannot be modified during an incremental update*. // For example, one cannot change the target between updates, but one can change source files, @@ -773,6 +775,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { cache.hash.add(pie); cache.hash.add(tsan); cache.hash.add(stack_check); + cache.hash.add(red_zone); cache.hash.add(link_mode); cache.hash.add(options.function_sections); cache.hash.add(strip); @@ -982,6 +985,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .valgrind = valgrind, .tsan = tsan, .stack_check = stack_check, + .red_zone = red_zone, .single_threaded = single_threaded, .verbose_link = options.verbose_link, .machine_code_model = options.machine_code_model, @@ -2256,6 +2260,12 @@ pub fn addCCArgs( try argv.append("-fsanitize=thread"); } + if (comp.bin_file.options.red_zone) { + try argv.append("-mred-zone"); + } else if (target_util.hasRedZone(target)) { + try argv.append("-mno-red-zone"); + } + switch (comp.bin_file.options.optimize_mode) { .Debug => { // windows c runtime requires -D_DEBUG if using debug libraries @@ -2960,6 +2970,7 @@ fn buildOutputFromZig( .function_sections = true, .want_sanitize_c = false, .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = false, .want_pic = comp.bin_file.options.pic, @@ -3198,6 +3209,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node .tsan_enabled = comp.bin_file.options.tsan, .function_sections = comp.bin_file.options.function_sections, .enable_stack_probing = comp.bin_file.options.stack_check, + .red_zone = comp.bin_file.options.red_zone, .enable_time_report = comp.time_report, .enable_stack_report = comp.stack_report, .test_is_evented = comp.test_evented_io, @@ -3342,6 +3354,7 @@ pub fn build_crt_file( .optimize_mode = comp.compilerRtOptMode(), .want_sanitize_c = false, .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = false, .want_pic = comp.bin_file.options.pic, diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index 52dc8c0280..c901c6045f 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -3803,7 +3803,14 @@ flagpd1("mno-qpx"), flagpd1("mno-rdpid"), flagpd1("mno-rdrnd"), flagpd1("mno-rdseed"), -flagpd1("mno-red-zone"), +.{ + .name = "mno-red-zone", + .syntax = .flag, + .zig_equivalent = .no_red_zone, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("mno-reference-types"), flagpd1("mno-relax"), flagpd1("mno-relax-all"), @@ -3901,7 +3908,14 @@ flagpd1("mrdseed"), flagpd1("mreassociate"), flagpd1("mrecip"), flagpd1("mrecord-mcount"), -flagpd1("mred-zone"), +.{ + .name = "mred-zone", + .syntax = .flag, + .zig_equivalent = .red_zone, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("mreference-types"), sepd1("mregparm"), flagpd1("mrelax"), diff --git a/src/glibc.zig b/src/glibc.zig index e7b7b1b1cf..b154bd530d 100644 --- a/src/glibc.zig +++ b/src/glibc.zig @@ -934,6 +934,7 @@ fn buildSharedLib( .optimize_mode = comp.compilerRtOptMode(), .want_sanitize_c = false, .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = false, .emit_h = null, diff --git a/src/libcxx.zig b/src/libcxx.zig index e79a0106e9..11989998e9 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -167,6 +167,7 @@ pub fn buildLibCXX(comp: *Compilation) !void { .link_mode = link_mode, .want_sanitize_c = false, .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = comp.bin_file.options.tsan, .want_pic = comp.bin_file.options.pic, @@ -284,6 +285,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { .link_mode = link_mode, .want_sanitize_c = false, .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = comp.bin_file.options.tsan, .want_pic = comp.bin_file.options.pic, diff --git a/src/libunwind.zig b/src/libunwind.zig index 7710b1aa77..c2d0475d6f 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -108,6 +108,7 @@ pub fn buildStaticLib(comp: *Compilation) !void { .link_mode = link_mode, .want_sanitize_c = false, .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = false, .want_pic = comp.bin_file.options.pic, diff --git a/src/link.zig b/src/link.zig index ffb69adee9..6914131bea 100644 --- a/src/link.zig +++ b/src/link.zig @@ -77,6 +77,7 @@ pub const Options = struct { valgrind: bool, tsan: bool, stack_check: bool, + red_zone: bool, single_threaded: bool, verbose_link: bool, dll_export_fns: bool, diff --git a/src/main.zig b/src/main.zig index b50f89e5c2..867aa348b1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -267,6 +267,8 @@ const usage_build_generic = \\ -mcmodel=[default|tiny| Limit range of code and data virtual addresses \\ small|kernel| \\ medium|large] + \\ -mred-zone Force-enable the "red-zone" + \\ -mno-red-zone Force-disable the "red-zone" \\ --name [name] Override root name (not a file path) \\ -O [mode] Choose what to optimize for \\ Debug (default) Optimizations off, safety on @@ -505,6 +507,7 @@ fn buildOutputType( var want_pie: ?bool = null; var want_sanitize_c: ?bool = null; var want_stack_check: ?bool = null; + var want_red_zone: ?bool = null; var want_valgrind: ?bool = null; var want_tsan: ?bool = null; var want_compiler_rt: ?bool = null; @@ -843,6 +846,10 @@ fn buildOutputType( want_stack_check = true; } else if (mem.eql(u8, arg, "-fno-stack-check")) { want_stack_check = false; + } else if (mem.eql(u8, arg, "-mred-zone")) { + want_red_zone = true; + } else if (mem.eql(u8, arg, "-mno-red-zone")) { + want_red_zone = false; } else if (mem.eql(u8, arg, "-fsanitize-c")) { want_sanitize_c = true; } else if (mem.eql(u8, arg, "-fno-sanitize-c")) { @@ -1068,6 +1075,8 @@ fn buildOutputType( .no_pic => want_pic = false, .pie => want_pie = true, .no_pie => want_pie = false, + .red_zone => want_red_zone = true, + .no_red_zone => want_red_zone = false, .nostdlib => ensure_libc_on_non_freestanding = false, .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false, .shared => { @@ -1760,6 +1769,7 @@ fn buildOutputType( .want_pie = want_pie, .want_sanitize_c = want_sanitize_c, .want_stack_check = want_stack_check, + .want_red_zone = want_red_zone, .want_valgrind = want_valgrind, .want_tsan = want_tsan, .want_compiler_rt = want_compiler_rt, @@ -2969,6 +2979,8 @@ pub const ClangArgIterator = struct { framework_dir, framework, nostdlibinc, + red_zone, + no_red_zone, }; const Args = struct { diff --git a/src/musl.zig b/src/musl.zig index a865e78623..0cb6983e28 100644 --- a/src/musl.zig +++ b/src/musl.zig @@ -206,6 +206,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { .optimize_mode = comp.compilerRtOptMode(), .want_sanitize_c = false, .want_stack_check = false, + .want_red_zone = comp.bin_file.options.red_zone, .want_valgrind = false, .want_tsan = false, .emit_h = null, diff --git a/src/stage1.zig b/src/stage1.zig index cf3a252ce8..44fd8e109e 100644 --- a/src/stage1.zig +++ b/src/stage1.zig @@ -119,6 +119,7 @@ pub const Module = extern struct { tsan_enabled: bool, function_sections: bool, enable_stack_probing: bool, + red_zone: bool, enable_time_report: bool, enable_stack_report: bool, test_is_evented: bool, diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index 24b54ad794..c235bb362d 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -2195,6 +2195,7 @@ struct CodeGen { bool link_mode_dynamic; bool dll_export_fns; bool have_stack_probing; + bool red_zone; bool function_sections; bool test_is_evented; bool valgrind_enabled; diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 386bc43086..10943483f4 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -514,6 +514,10 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { maybe_import_dll(g, llvm_fn, linkage); } + if (!g->red_zone) { + addLLVMFnAttr(llvm_fn, "noredzone"); + } + if (fn->alignstack_value != 0) { addLLVMFnAttrInt(llvm_fn, "alignstack", fn->alignstack_value); } diff --git a/src/stage1/stage1.cpp b/src/stage1/stage1.cpp index 1195a83931..d680121577 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_stack_probing = stage1->enable_stack_probing; + g->red_zone = stage1->red_zone; g->is_single_threaded = stage1->is_single_threaded; g->valgrind_enabled = stage1->valgrind_enabled; g->tsan_enabled = stage1->tsan_enabled; diff --git a/src/stage1/stage1.h b/src/stage1/stage1.h index dbf6491699..6db3621cf5 100644 --- a/src/stage1/stage1.h +++ b/src/stage1/stage1.h @@ -188,6 +188,7 @@ struct ZigStage1 { bool tsan_enabled; bool function_sections; bool enable_stack_probing; + bool red_zone; bool enable_time_report; bool enable_stack_report; bool test_is_evented; diff --git a/src/target.zig b/src/target.zig index daac577c7b..c3df682ce0 100644 --- a/src/target.zig +++ b/src/target.zig @@ -349,3 +349,21 @@ pub fn defaultCompilerRtOptimizeMode(target: std.Target) std.builtin.Mode { return .ReleaseFast; } } + +pub fn hasRedZone(target: std.Target) bool { + return switch (target.cpu.arch) { + .x86_64, + .i386, + .wasm32, + .wasm64, + .powerpc, + .powerpc64, + .powerpc64le, + .aarch64, + .aarch64_be, + .aarch64_32, + => true, + + else => false, + }; +} diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index ad380e0139..189a2ed7fa 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -248,6 +248,14 @@ const known_options = [_]KnownOpt{ .name = "mtune", .ident = "mcpu", }, + .{ + .name = "mred-zone", + .ident = "red_zone", + }, + .{ + .name = "mno-red-zone", + .ident = "no_red_zone", + }, .{ .name = "MD", .ident = "dep_file", @@ -340,9 +348,9 @@ pub fn main() anyerror!void { const child_args = [_][]const u8{ llvm_tblgen_exe, "--dump-json", - try std.fmt.allocPrint(allocator, "{}/clang/include/clang/Driver/Options.td", .{llvm_src_root}), - try std.fmt.allocPrint(allocator, "-I={}/llvm/include", .{llvm_src_root}), - try std.fmt.allocPrint(allocator, "-I={}/clang/include/clang/Driver", .{llvm_src_root}), + try std.fmt.allocPrint(allocator, "{s}/clang/include/clang/Driver/Options.td", .{llvm_src_root}), + try std.fmt.allocPrint(allocator, "-I={s}/llvm/include", .{llvm_src_root}), + try std.fmt.allocPrint(allocator, "-I={s}/clang/include/clang/Driver", .{llvm_src_root}), }; const child_result = try std.ChildProcess.exec(.{ @@ -351,11 +359,11 @@ pub fn main() anyerror!void { .max_output_bytes = 100 * 1024 * 1024, }); - std.debug.warn("{}\n", .{child_result.stderr}); + std.debug.warn("{s}\n", .{child_result.stderr}); const json_text = switch (child_result.term) { .Exited => |code| if (code == 0) child_result.stdout else { - std.debug.warn("llvm-tblgen exited with code {}\n", .{code}); + std.debug.warn("llvm-tblgen exited with code {d}\n", .{code}); std.process.exit(1); }, else => { @@ -412,7 +420,7 @@ pub fn main() anyerror!void { } else if (std.mem.eql(u8, prefix, "/")) { pslash = true; } else { - std.debug.warn("{} has unrecognized prefix '{}'\n", .{ name, prefix }); + std.debug.warn("{s} has unrecognized prefix '{s}'\n", .{ name, prefix }); std.process.exit(1); } } @@ -422,7 +430,7 @@ pub fn main() anyerror!void { // `-MT foo` is ambiguous because there is also an -MT flag // The canonical way to specify the flag is with `/MT` and so we make this // the only way. - try stdout.print("flagpsl(\"{}\"),\n", .{name}); + try stdout.print("flagpsl(\"{s}\"),\n", .{name}); } else if (knownOption(name)) |ident| { // Workaround the fact that in 'Options.td' -Ofast is listed as 'joined' @@ -430,34 +438,34 @@ pub fn main() anyerror!void { try stdout.print( \\.{{ - \\ .name = "{}", - \\ .syntax = {}, - \\ .zig_equivalent = .{}, - \\ .pd1 = {}, - \\ .pd2 = {}, - \\ .psl = {}, + \\ .name = "{s}", + \\ .syntax = {s}, + \\ .zig_equivalent = .{s}, + \\ .pd1 = {s}, + \\ .pd2 = {s}, + \\ .psl = {s}, \\}}, \\ , .{ name, final_syntax, ident, pd1, pd2, pslash }); } else if (pd1 and !pd2 and !pslash and syntax == .flag) { - try stdout.print("flagpd1(\"{}\"),\n", .{name}); + try stdout.print("flagpd1(\"{s}\"),\n", .{name}); } else if (!pd1 and !pd2 and pslash and syntax == .flag) { - try stdout.print("flagpsl(\"{}\"),\n", .{name}); + try stdout.print("flagpsl(\"{s}\"),\n", .{name}); } else if (pd1 and !pd2 and !pslash and syntax == .joined) { - try stdout.print("joinpd1(\"{}\"),\n", .{name}); + try stdout.print("joinpd1(\"{s}\"),\n", .{name}); } else if (pd1 and !pd2 and !pslash and syntax == .joined_or_separate) { - try stdout.print("jspd1(\"{}\"),\n", .{name}); + try stdout.print("jspd1(\"{s}\"),\n", .{name}); } else if (pd1 and !pd2 and !pslash and syntax == .separate) { - try stdout.print("sepd1(\"{}\"),\n", .{name}); + try stdout.print("sepd1(\"{s}\"),\n", .{name}); } else { try stdout.print( \\.{{ - \\ .name = "{}", - \\ .syntax = {}, + \\ .name = "{s}", + \\ .syntax = {s}, \\ .zig_equivalent = .other, - \\ .pd1 = {}, - \\ .pd2 = {}, - \\ .psl = {}, + \\ .pd1 = {s}, + \\ .pd2 = {s}, + \\ .psl = {s}, \\}}, \\ , .{ name, syntax, pd1, pd2, pslash }); @@ -506,8 +514,8 @@ const Syntax = union(enum) { out_stream: anytype, ) !void { switch (self) { - .multi_arg => |n| return out_stream.print(".{{.{}={}}}", .{ @tagName(self), n }), - else => return out_stream.print(".{}", .{@tagName(self)}), + .multi_arg => |n| return out_stream.print(".{{.{s}={}}}", .{ @tagName(self), n }), + else => return out_stream.print(".{s}", .{@tagName(self)}), } } }; @@ -559,9 +567,9 @@ fn objSyntax(obj: *json.ObjectMap) Syntax { return .flag; } const key = obj.get("!name").?.String; - std.debug.warn("{} (key {}) has unrecognized superclasses:\n", .{ name, key }); + std.debug.warn("{s} (key {s}) has unrecognized superclasses:\n", .{ name, key }); for (obj.get("!superclasses").?.Array.items) |superclass_json| { - std.debug.warn(" {}\n", .{superclass_json.String}); + std.debug.warn(" {s}\n", .{superclass_json.String}); } std.process.exit(1); } @@ -612,7 +620,7 @@ fn objectLessThan(context: void, a: *json.ObjectMap, b: *json.ObjectMap) bool { fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn { file.writer().print( - \\Usage: {} /path/to/llvm-tblgen /path/to/git/llvm/llvm-project + \\Usage: {s} /path/to/llvm-tblgen /path/to/git/llvm/llvm-project \\Alternative Usage: zig run /path/to/git/zig/tools/update_clang_options.zig -- /path/to/llvm-tblgen /path/to/git/llvm/llvm-project \\ \\Prints to stdout Zig code which you can use to replace the file src/clang_options_data.zig.