| ... | ... | @@ -173,6 +173,7 @@ astgen_wait_group: WaitGroup = .{}, |
| 173 | 173 | /// TODO: Remove this when Stage2 becomes the default compiler as it will already have this information. |
| 174 | 174 | export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{}, |
| 175 | 175 | |
| 176 | pub const default_stack_protector_buffer_size = 4; |
| 176 | 177 | pub const SemaError = Module.SemaError; |
| 177 | 178 | |
| 178 | 179 | pub const CRTFile = struct { |
| ... | ... | @@ -837,6 +838,10 @@ pub const InitOptions = struct { |
| 837 | 838 | want_pie: ?bool = null, |
| 838 | 839 | want_sanitize_c: ?bool = null, |
| 839 | 840 | want_stack_check: ?bool = null, |
| 841 | /// null means default. |
| 842 | /// 0 means no stack protector. |
| 843 | /// other number means stack protection with that buffer size. |
| 844 | want_stack_protector: ?u32 = null, |
| 840 | 845 | want_red_zone: ?bool = null, |
| 841 | 846 | omit_frame_pointer: ?bool = null, |
| 842 | 847 | want_valgrind: ?bool = null, |
| ... | ... | @@ -1014,6 +1019,15 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1014 | 1019 | return error.ExportTableAndImportTableConflict; |
| 1015 | 1020 | } |
| 1016 | 1021 | |
| 1022 | // The `have_llvm` condition is here only because native backends cannot yet build compiler-rt. |
| 1023 | // Once they are capable this condition could be removed. When removing this condition, |
| 1024 | // also test the use case of `build-obj -fcompiler-rt` with the native backends |
| 1025 | // and make sure the compiler-rt symbols are emitted. |
| 1026 | const capable_of_building_compiler_rt = build_options.have_llvm; |
| 1027 | |
| 1028 | const capable_of_building_zig_libc = build_options.have_llvm; |
| 1029 | const capable_of_building_ssp = build_options.have_llvm; |
| 1030 | |
| 1017 | 1031 | const comp: *Compilation = comp: { |
| 1018 | 1032 | // For allocations that have the same lifetime as Compilation. This arena is used only during this |
| 1019 | 1033 | // initialization and then is freed in deinit(). |
| ... | ... | @@ -1289,11 +1303,36 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1289 | 1303 | |
| 1290 | 1304 | const sanitize_c = options.want_sanitize_c orelse is_safe_mode; |
| 1291 | 1305 | |
| 1292 | | const stack_check: bool = b: { |
| 1293 | | if (!target_util.supportsStackProbing(options.target)) |
| 1294 | | break :b false; |
| 1295 | | break :b options.want_stack_check orelse is_safe_mode; |
| 1306 | const stack_check: bool = options.want_stack_check orelse b: { |
| 1307 | if (!target_util.supportsStackProbing(options.target)) break :b false; |
| 1308 | break :b is_safe_mode; |
| 1296 | 1309 | }; |
| 1310 | if (stack_check and !target_util.supportsStackProbing(options.target)) |
| 1311 | return error.StackCheckUnsupportedByTarget; |
| 1312 | |
| 1313 | const stack_protector: u32 = options.want_stack_protector orelse b: { |
| 1314 | if (!target_util.supportsStackProtector(options.target)) break :b @as(u32, 0); |
| 1315 | |
| 1316 | // This logic is checking for linking libc because otherwise our start code |
| 1317 | // which is trying to set up TLS (i.e. the fs/gs registers) but the stack |
| 1318 | // protection code depends on fs/gs registers being already set up. |
| 1319 | // If we were able to annotate start code, or perhaps the entire std lib, |
| 1320 | // as being exempt from stack protection checks, we could change this logic |
| 1321 | // to supporting stack protection even when not linking libc. |
| 1322 | // TODO file issue about this |
| 1323 | if (!link_libc) break :b 0; |
| 1324 | if (!capable_of_building_ssp) break :b 0; |
| 1325 | if (is_safe_mode) break :b default_stack_protector_buffer_size; |
| 1326 | break :b 0; |
| 1327 | }; |
| 1328 | if (stack_protector != 0) { |
| 1329 | if (!target_util.supportsStackProtector(options.target)) |
| 1330 | return error.StackProtectorUnsupportedByTarget; |
| 1331 | if (!capable_of_building_ssp) |
| 1332 | return error.StackProtectorUnsupportedByBackend; |
| 1333 | if (!link_libc) |
| 1334 | return error.StackProtectorUnavailableWithoutLibC; |
| 1335 | } |
| 1297 | 1336 | |
| 1298 | 1337 | const valgrind: bool = b: { |
| 1299 | 1338 | if (!target_util.hasValgrindSupport(options.target)) |
| ... | ... | @@ -1378,6 +1417,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1378 | 1417 | cache.hash.add(unwind_tables); |
| 1379 | 1418 | cache.hash.add(tsan); |
| 1380 | 1419 | cache.hash.add(stack_check); |
| 1420 | cache.hash.add(stack_protector); |
| 1381 | 1421 | cache.hash.add(red_zone); |
| 1382 | 1422 | cache.hash.add(omit_frame_pointer); |
| 1383 | 1423 | cache.hash.add(link_mode); |
| ... | ... | @@ -1741,6 +1781,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1741 | 1781 | .valgrind = valgrind, |
| 1742 | 1782 | .tsan = tsan, |
| 1743 | 1783 | .stack_check = stack_check, |
| 1784 | .stack_protector = stack_protector, |
| 1744 | 1785 | .red_zone = red_zone, |
| 1745 | 1786 | .omit_frame_pointer = omit_frame_pointer, |
| 1746 | 1787 | .single_threaded = single_threaded, |
| ... | ... | @@ -1822,6 +1863,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1822 | 1863 | }; |
| 1823 | 1864 | errdefer comp.destroy(); |
| 1824 | 1865 | |
| 1866 | const target = comp.getTarget(); |
| 1867 | |
| 1825 | 1868 | // Add a `CObject` for each `c_source_files`. |
| 1826 | 1869 | try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len); |
| 1827 | 1870 | for (options.c_source_files) |c_source_file| { |
| ... | ... | @@ -1837,11 +1880,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1837 | 1880 | |
| 1838 | 1881 | const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null; |
| 1839 | 1882 | |
| 1840 | | if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and |
| 1841 | | options.target.ofmt != .c) |
| 1842 | | { |
| 1843 | | if (comp.getTarget().isDarwin()) { |
| 1844 | | switch (comp.getTarget().abi) { |
| 1883 | if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and target.ofmt != .c) { |
| 1884 | if (target.isDarwin()) { |
| 1885 | switch (target.abi) { |
| 1845 | 1886 | .none, |
| 1846 | 1887 | .simulator, |
| 1847 | 1888 | .macabi, |
| ... | ... | @@ -1852,9 +1893,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1852 | 1893 | // If we need to build glibc for the target, add work items for it. |
| 1853 | 1894 | // We go through the work queue so that building can be done in parallel. |
| 1854 | 1895 | if (comp.wantBuildGLibCFromSource()) { |
| 1855 | | if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; |
| 1896 | if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; |
| 1856 | 1897 | |
| 1857 | | if (glibc.needsCrtiCrtn(comp.getTarget())) { |
| 1898 | if (glibc.needsCrtiCrtn(target)) { |
| 1858 | 1899 | try comp.work_queue.write(&[_]Job{ |
| 1859 | 1900 | .{ .glibc_crt_file = .crti_o }, |
| 1860 | 1901 | .{ .glibc_crt_file = .crtn_o }, |
| ... | ... | @@ -1867,10 +1908,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1867 | 1908 | }); |
| 1868 | 1909 | } |
| 1869 | 1910 | if (comp.wantBuildMuslFromSource()) { |
| 1870 | | if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; |
| 1911 | if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; |
| 1871 | 1912 | |
| 1872 | 1913 | try comp.work_queue.ensureUnusedCapacity(6); |
| 1873 | | if (musl.needsCrtiCrtn(comp.getTarget())) { |
| 1914 | if (musl.needsCrtiCrtn(target)) { |
| 1874 | 1915 | comp.work_queue.writeAssumeCapacity(&[_]Job{ |
| 1875 | 1916 | .{ .musl_crt_file = .crti_o }, |
| 1876 | 1917 | .{ .musl_crt_file = .crtn_o }, |
| ... | ... | @@ -1887,7 +1928,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1887 | 1928 | }); |
| 1888 | 1929 | } |
| 1889 | 1930 | if (comp.wantBuildWasiLibcFromSource()) { |
| 1890 | | if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; |
| 1931 | if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; |
| 1891 | 1932 | |
| 1892 | 1933 | const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs; |
| 1893 | 1934 | try comp.work_queue.ensureUnusedCapacity(wasi_emulated_libs.len + 2); // worst-case we need all components |
| ... | ... | @@ -1902,7 +1943,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1902 | 1943 | }); |
| 1903 | 1944 | } |
| 1904 | 1945 | if (comp.wantBuildMinGWFromSource()) { |
| 1905 | | if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; |
| 1946 | if (!target_util.canBuildLibC(target)) return error.LibCUnavailable; |
| 1906 | 1947 | |
| 1907 | 1948 | const static_lib_jobs = [_]Job{ |
| 1908 | 1949 | .{ .mingw_crt_file = .mingw32_lib }, |
| ... | ... | @@ -1921,7 +1962,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1921 | 1962 | } |
| 1922 | 1963 | } |
| 1923 | 1964 | // Generate Windows import libs. |
| 1924 | | if (comp.getTarget().os.tag == .windows) { |
| 1965 | if (target.os.tag == .windows) { |
| 1925 | 1966 | const count = comp.bin_file.options.system_libs.count(); |
| 1926 | 1967 | try comp.work_queue.ensureUnusedCapacity(count); |
| 1927 | 1968 | var i: usize = 0; |
| ... | ... | @@ -1940,15 +1981,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1940 | 1981 | try comp.work_queue.writeItem(.libtsan); |
| 1941 | 1982 | } |
| 1942 | 1983 | |
| 1943 | | // The `have_llvm` condition is here only because native backends cannot yet build compiler-rt. |
| 1944 | | // Once they are capable this condition could be removed. When removing this condition, |
| 1945 | | // also test the use case of `build-obj -fcompiler-rt` with the native backends |
| 1946 | | // and make sure the compiler-rt symbols are emitted. |
| 1947 | | const capable_of_building_compiler_rt = build_options.have_llvm; |
| 1948 | | |
| 1949 | | const capable_of_building_zig_libc = build_options.have_llvm; |
| 1950 | | const capable_of_building_ssp = comp.bin_file.options.use_stage1; |
| 1951 | | |
| 1952 | 1984 | if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) { |
| 1953 | 1985 | if (is_exe_or_dyn_lib) { |
| 1954 | 1986 | log.debug("queuing a job to build compiler_rt_lib", .{}); |
| ... | ... | @@ -1962,8 +1994,11 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1962 | 1994 | } |
| 1963 | 1995 | } |
| 1964 | 1996 | if (needs_c_symbols) { |
| 1965 | | // MinGW provides no libssp, use our own implementation. |
| 1966 | | if (comp.getTarget().isMinGW() and capable_of_building_ssp) { |
| 1997 | // Related: https://github.com/ziglang/zig/issues/7265. |
| 1998 | if (comp.bin_file.options.stack_protector != 0 and |
| 1999 | (!comp.bin_file.options.link_libc or |
| 2000 | !target_util.libcProvidesStackProtector(target))) |
| 2001 | { |
| 1967 | 2002 | try comp.work_queue.writeItem(.{ .libssp = {} }); |
| 1968 | 2003 | } |
| 1969 | 2004 | |
| ... | ... | @@ -4123,6 +4158,17 @@ pub fn addCCArgs( |
| 4123 | 4158 | try argv.append("-fno-omit-frame-pointer"); |
| 4124 | 4159 | } |
| 4125 | 4160 | |
| 4161 | const ssp_buf_size = comp.bin_file.options.stack_protector; |
| 4162 | if (ssp_buf_size != 0) { |
| 4163 | try argv.appendSlice(&[_][]const u8{ |
| 4164 | "-fstack-protector-strong", |
| 4165 | "--param", |
| 4166 | try std.fmt.allocPrint(arena, "ssp-buffer-size={d}", .{ssp_buf_size}), |
| 4167 | }); |
| 4168 | } else { |
| 4169 | try argv.append("-fno-stack-protector"); |
| 4170 | } |
| 4171 | |
| 4126 | 4172 | switch (comp.bin_file.options.optimize_mode) { |
| 4127 | 4173 | .Debug => { |
| 4128 | 4174 | // windows c runtime requires -D_DEBUG if using debug libraries |
| ... | ... | @@ -4131,27 +4177,12 @@ pub fn addCCArgs( |
| 4131 | 4177 | // to -O1. Besides potentially impairing debugging, -O1/-Og significantly |
| 4132 | 4178 | // increases compile times. |
| 4133 | 4179 | try argv.append("-O0"); |
| 4134 | | |
| 4135 | | if (comp.bin_file.options.link_libc and target.os.tag != .wasi) { |
| 4136 | | try argv.append("-fstack-protector-strong"); |
| 4137 | | try argv.append("--param"); |
| 4138 | | try argv.append("ssp-buffer-size=4"); |
| 4139 | | } else { |
| 4140 | | try argv.append("-fno-stack-protector"); |
| 4141 | | } |
| 4142 | 4180 | }, |
| 4143 | 4181 | .ReleaseSafe => { |
| 4144 | 4182 | // See the comment in the BuildModeFastRelease case for why we pass -O2 rather |
| 4145 | 4183 | // than -O3 here. |
| 4146 | 4184 | try argv.append("-O2"); |
| 4147 | | if (comp.bin_file.options.link_libc and target.os.tag != .wasi) { |
| 4148 | | try argv.append("-D_FORTIFY_SOURCE=2"); |
| 4149 | | try argv.append("-fstack-protector-strong"); |
| 4150 | | try argv.append("--param"); |
| 4151 | | try argv.append("ssp-buffer-size=4"); |
| 4152 | | } else { |
| 4153 | | try argv.append("-fno-stack-protector"); |
| 4154 | | } |
| 4185 | try argv.append("-D_FORTIFY_SOURCE=2"); |
| 4155 | 4186 | }, |
| 4156 | 4187 | .ReleaseFast => { |
| 4157 | 4188 | try argv.append("-DNDEBUG"); |
| ... | ... | @@ -4161,12 +4192,10 @@ pub fn addCCArgs( |
| 4161 | 4192 | // Zig code than it is for C code. Also, C programmers are used to their code |
| 4162 | 4193 | // running in -O2 and thus the -O3 path has been tested less. |
| 4163 | 4194 | try argv.append("-O2"); |
| 4164 | | try argv.append("-fno-stack-protector"); |
| 4165 | 4195 | }, |
| 4166 | 4196 | .ReleaseSmall => { |
| 4167 | 4197 | try argv.append("-DNDEBUG"); |
| 4168 | 4198 | try argv.append("-Os"); |
| 4169 | | try argv.append("-fno-stack-protector"); |
| 4170 | 4199 | }, |
| 4171 | 4200 | } |
| 4172 | 4201 | |
| ... | ... | @@ -5031,6 +5060,7 @@ fn buildOutputFromZig( |
| 5031 | 5060 | .use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1, |
| 5032 | 5061 | .want_sanitize_c = false, |
| 5033 | 5062 | .want_stack_check = false, |
| 5063 | .want_stack_protector = 0, |
| 5034 | 5064 | .want_red_zone = comp.bin_file.options.red_zone, |
| 5035 | 5065 | .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, |
| 5036 | 5066 | .want_valgrind = false, |
| ... | ... | @@ -5311,6 +5341,7 @@ pub fn build_crt_file( |
| 5311 | 5341 | .optimize_mode = comp.compilerRtOptMode(), |
| 5312 | 5342 | .want_sanitize_c = false, |
| 5313 | 5343 | .want_stack_check = false, |
| 5344 | .want_stack_protector = 0, |
| 5314 | 5345 | .want_red_zone = comp.bin_file.options.red_zone, |
| 5315 | 5346 | .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, |
| 5316 | 5347 | .want_valgrind = false, |