| author | |
| committer | |
| log | d44486b274a916823fcf6045a6400ef51e07d544 |
| tree | c12a3a3923b644d219f815630941073d99d31889 |
| parent | 2aff27d92247eed3b64ffc68da8fae9e5994ea0b |
Unlike glibc and musl, MinGW provides no libssp symbols leading to
countless compile errors if FORTIFY_SOURCE is defined.
Add a (incomplete) implementation of libssp written in Zig so that
linking succeeds.
Closes #64925 files changed, 276 insertions(+), 53 deletions(-)
lib/std/special/c.zig+113-33| ... | ... | @@ -35,6 +35,10 @@ comptime { |
| 35 | 35 | @export(strncmp, .{ .name = "strncmp", .linkage = .Strong }); |
| 36 | 36 | @export(strerror, .{ .name = "strerror", .linkage = .Strong }); |
| 37 | 37 | @export(strlen, .{ .name = "strlen", .linkage = .Strong }); |
| 38 | @export(strcpy, .{ .name = "strcpy", .linkage = .Strong }); | |
| 39 | @export(strncpy, .{ .name = "strncpy", .linkage = .Strong }); | |
| 40 | @export(strcat, .{ .name = "strcat", .linkage = .Strong }); | |
| 41 | @export(strncat, .{ .name = "strncat", .linkage = .Strong }); | |
| 38 | 42 | } else if (is_msvc) { |
| 39 | 43 | @export(_fltused, .{ .name = "_fltused", .linkage = .Strong }); |
| 40 | 44 | } |
| ... | ... | @@ -47,6 +51,90 @@ fn wasm_start() callconv(.C) void { |
| 47 | 51 | _ = main(0, undefined); |
| 48 | 52 | } |
| 49 | 53 | |
| 54 | fn strcpy(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 { | |
| 55 | var i: usize = 0; | |
| 56 | while (src[i] != 0) : (i += 1) { | |
| 57 | dest[i] = src[i]; | |
| 58 | } | |
| 59 | dest[i] = 0; | |
| 60 | ||
| 61 | return dest; | |
| 62 | } | |
| 63 | ||
| 64 | test "strcpy" { | |
| 65 | var s1: [9:0]u8 = undefined; | |
| 66 | ||
| 67 | s1[0] = 0; | |
| 68 | _ = strcpy(&s1, "foobarbaz"); | |
| 69 | std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1)); | |
| 70 | } | |
| 71 | ||
| 72 | fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.C) [*:0]u8 { | |
| 73 | var i: usize = 0; | |
| 74 | while (i < n and src[i] != 0) : (i += 1) { | |
| 75 | dest[i] = src[i]; | |
| 76 | } | |
| 77 | while (i < n) : (i += 1) { | |
| 78 | dest[i] = 0; | |
| 79 | } | |
| 80 | ||
| 81 | return dest; | |
| 82 | } | |
| 83 | ||
| 84 | test "strncpy" { | |
| 85 | var s1: [9:0]u8 = undefined; | |
| 86 | ||
| 87 | s1[0] = 0; | |
| 88 | _ = strncpy(&s1, "foobarbaz", 9); | |
| 89 | std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1)); | |
| 90 | } | |
| 91 | ||
| 92 | fn strcat(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 { | |
| 93 | var dest_end: usize = 0; | |
| 94 | while (dest[dest_end] != 0) : (dest_end += 1) {} | |
| 95 | ||
| 96 | var i: usize = 0; | |
| 97 | while (src[i] != 0) : (i += 1) { | |
| 98 | dest[dest_end + i] = src[i]; | |
| 99 | } | |
| 100 | dest[dest_end + i] = 0; | |
| 101 | ||
| 102 | return dest; | |
| 103 | } | |
| 104 | ||
| 105 | test "strcat" { | |
| 106 | var s1: [9:0]u8 = undefined; | |
| 107 | ||
| 108 | s1[0] = 0; | |
| 109 | _ = strcat(&s1, "foo"); | |
| 110 | _ = strcat(&s1, "bar"); | |
| 111 | _ = strcat(&s1, "baz"); | |
| 112 | std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1)); | |
| 113 | } | |
| 114 | ||
| 115 | fn strncat(dest: [*:0]u8, src: [*:0]const u8, avail: usize) callconv(.C) [*:0]u8 { | |
| 116 | var dest_end: usize = 0; | |
| 117 | while (dest[dest_end] != 0) : (dest_end += 1) {} | |
| 118 | ||
| 119 | var i: usize = 0; | |
| 120 | while (i < avail and src[i] != 0) : (i += 1) { | |
| 121 | dest[dest_end + i] = src[i]; | |
| 122 | } | |
| 123 | dest[dest_end + i] = 0; | |
| 124 | ||
| 125 | return dest; | |
| 126 | } | |
| 127 | ||
| 128 | test "strncat" { | |
| 129 | var s1: [9:0]u8 = undefined; | |
| 130 | ||
| 131 | s1[0] = 0; | |
| 132 | _ = strncat(&s1, "foo1111", 3); | |
| 133 | _ = strncat(&s1, "bar1111", 3); | |
| 134 | _ = strncat(&s1, "baz1111", 3); | |
| 135 | std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1)); | |
| 136 | } | |
| 137 | ||
| 50 | 138 | fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int { |
| 51 | 139 | return std.cstr.cmp(s1, s2); |
| 52 | 140 | } |
| ... | ... | @@ -92,7 +180,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn |
| 92 | 180 | while (true) {} |
| 93 | 181 | } |
| 94 | 182 | |
| 95 | export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 { | |
| 183 | export fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8 { | |
| 96 | 184 | @setRuntimeSafety(false); |
| 97 | 185 | |
| 98 | 186 | var index: usize = 0; |
| ... | ... | @@ -102,7 +190,13 @@ export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 { |
| 102 | 190 | return dest; |
| 103 | 191 | } |
| 104 | 192 | |
| 105 | export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]u8 { | |
| 193 | export fn __memset(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { | |
| 194 | if (dest_n < n) | |
| 195 | @panic("buffer overflow"); | |
| 196 | return memset(dest, c, n); | |
| 197 | } | |
| 198 | ||
| 199 | export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 { | |
| 106 | 200 | @setRuntimeSafety(false); |
| 107 | 201 | |
| 108 | 202 | var index: usize = 0; |
| ... | ... | @@ -112,7 +206,7 @@ export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*] |
| 112 | 206 | return dest; |
| 113 | 207 | } |
| 114 | 208 | |
| 115 | export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 { | |
| 209 | export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 { | |
| 116 | 210 | @setRuntimeSafety(false); |
| 117 | 211 | |
| 118 | 212 | if (@ptrToInt(dest) < @ptrToInt(src)) { |
| ... | ... | @@ -131,7 +225,7 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 { |
| 131 | 225 | return dest; |
| 132 | 226 | } |
| 133 | 227 | |
| 134 | export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) isize { | |
| 228 | export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) isize { | |
| 135 | 229 | @setRuntimeSafety(false); |
| 136 | 230 | |
| 137 | 231 | var index: usize = 0; |
| ... | ... | @@ -146,17 +240,17 @@ export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) isize { |
| 146 | 240 | } |
| 147 | 241 | |
| 148 | 242 | test "test_memcmp" { |
| 149 | const base_arr = []u8{ 1, 1, 1 }; | |
| 150 | const arr1 = []u8{ 1, 1, 1 }; | |
| 151 | const arr2 = []u8{ 1, 0, 1 }; | |
| 152 | const arr3 = []u8{ 1, 2, 1 }; | |
| 243 | const base_arr = &[_]u8{ 1, 1, 1 }; | |
| 244 | const arr1 = &[_]u8{ 1, 1, 1 }; | |
| 245 | const arr2 = &[_]u8{ 1, 0, 1 }; | |
| 246 | const arr3 = &[_]u8{ 1, 2, 1 }; | |
| 153 | 247 | |
| 154 | std.testing.expect(memcmp(base_arr[0..].ptr, arr1[0..].ptr, base_arr.len) == 0); | |
| 155 | std.testing.expect(memcmp(base_arr[0..].ptr, arr2[0..].ptr, base_arr.len) > 0); | |
| 156 | std.testing.expect(memcmp(base_arr[0..].ptr, arr3[0..].ptr, base_arr.len) < 0); | |
| 248 | std.testing.expect(memcmp(base_arr[0..], arr1[0..], base_arr.len) == 0); | |
| 249 | std.testing.expect(memcmp(base_arr[0..], arr2[0..], base_arr.len) > 0); | |
| 250 | std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0); | |
| 157 | 251 | } |
| 158 | 252 | |
| 159 | export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) isize { | |
| 253 | export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) isize { | |
| 160 | 254 | @setRuntimeSafety(false); |
| 161 | 255 | |
| 162 | 256 | var index: usize = 0; |
| ... | ... | @@ -170,30 +264,21 @@ export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) i |
| 170 | 264 | } |
| 171 | 265 | |
| 172 | 266 | test "test_bcmp" { |
| 173 | const base_arr = []u8{ 1, 1, 1 }; | |
| 174 | const arr1 = []u8{ 1, 1, 1 }; | |
| 175 | const arr2 = []u8{ 1, 0, 1 }; | |
| 176 | const arr3 = []u8{ 1, 2, 1 }; | |
| 267 | const base_arr = &[_]u8{ 1, 1, 1 }; | |
| 268 | const arr1 = &[_]u8{ 1, 1, 1 }; | |
| 269 | const arr2 = &[_]u8{ 1, 0, 1 }; | |
| 270 | const arr3 = &[_]u8{ 1, 2, 1 }; | |
| 177 | 271 | |
| 178 | std.testing.expect(bcmp(base_arr[0..].ptr, arr1[0..].ptr, base_arr.len) == 0); | |
| 179 | std.testing.expect(bcmp(base_arr[0..].ptr, arr2[0..].ptr, base_arr.len) != 0); | |
| 180 | std.testing.expect(bcmp(base_arr[0..].ptr, arr3[0..].ptr, base_arr.len) != 0); | |
| 272 | std.testing.expect(bcmp(base_arr[0..], arr1[0..], base_arr.len) == 0); | |
| 273 | std.testing.expect(bcmp(base_arr[0..], arr2[0..], base_arr.len) != 0); | |
| 274 | std.testing.expect(bcmp(base_arr[0..], arr3[0..], base_arr.len) != 0); | |
| 181 | 275 | } |
| 182 | 276 | |
| 183 | 277 | comptime { |
| 184 | if (builtin.mode != builtin.Mode.ReleaseFast and | |
| 185 | builtin.mode != builtin.Mode.ReleaseSmall and | |
| 186 | builtin.os.tag != .windows) | |
| 187 | { | |
| 188 | @export(__stack_chk_fail, .{ .name = "__stack_chk_fail" }); | |
| 189 | } | |
| 190 | 278 | if (builtin.os.tag == .linux) { |
| 191 | 279 | @export(clone, .{ .name = "clone" }); |
| 192 | 280 | } |
| 193 | 281 | } |
| 194 | fn __stack_chk_fail() callconv(.C) noreturn { | |
| 195 | @panic("stack smashing detected"); | |
| 196 | } | |
| 197 | 282 | |
| 198 | 283 | // TODO we should be able to put this directly in std/linux/x86_64.zig but |
| 199 | 284 | // it causes a segfault in release mode. this is a workaround of calling it |
| ... | ... | @@ -416,7 +501,6 @@ fn clone() callconv(.Naked) void { |
| 416 | 501 | \\ # move syscall number into r0 |
| 417 | 502 | \\ li 0, 120 |
| 418 | 503 | \\ sc |
| 419 | ||
| 420 | 504 | \\ # check for syscall error |
| 421 | 505 | \\ bns+ 1f # jump to label 1 if no summary overflow. |
| 422 | 506 | \\ #else |
| ... | ... | @@ -424,10 +508,8 @@ fn clone() callconv(.Naked) void { |
| 424 | 508 | \\1: |
| 425 | 509 | \\ # compare sc result with 0 |
| 426 | 510 | \\ cmpwi cr7, 3, 0 |
| 427 | ||
| 428 | 511 | \\ # if not 0, jump to end |
| 429 | 512 | \\ bne cr7, 2f |
| 430 | ||
| 431 | 513 | \\ #else: we're the child |
| 432 | 514 | \\ #call funcptr: move arg (d) into r3 |
| 433 | 515 | \\ mr 3, 31 |
| ... | ... | @@ -438,13 +520,11 @@ fn clone() callconv(.Naked) void { |
| 438 | 520 | \\ # mov SYS_exit into r0 (the exit param is already in r3) |
| 439 | 521 | \\ li 0, 1 |
| 440 | 522 | \\ sc |
| 441 | ||
| 442 | 523 | \\2: |
| 443 | 524 | \\ # restore stack |
| 444 | 525 | \\ lwz 30, 0(1) |
| 445 | 526 | \\ lwz 31, 4(1) |
| 446 | 527 | \\ addi 1, 1, 16 |
| 447 | ||
| 448 | 528 | \\ blr |
| 449 | 529 | ); |
| 450 | 530 | }, |
lib/std/special/compiler_rt.zig-19| ... | ... | @@ -284,11 +284,6 @@ comptime { |
| 284 | 284 | @export(@import("compiler_rt/stack_probe.zig").__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage }); |
| 285 | 285 | } |
| 286 | 286 | |
| 287 | if (is_mingw) { | |
| 288 | @export(__stack_chk_fail, .{ .name = "__stack_chk_fail", .linkage = strong_linkage }); | |
| 289 | @export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = strong_linkage }); | |
| 290 | } | |
| 291 | ||
| 292 | 287 | switch (builtin.arch) { |
| 293 | 288 | .i386 => { |
| 294 | 289 | @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage }); |
| ... | ... | @@ -311,9 +306,6 @@ comptime { |
| 311 | 306 | else => {}, |
| 312 | 307 | } |
| 313 | 308 | } else { |
| 314 | if (std.Target.current.isGnuLibC() and builtin.link_libc) { | |
| 315 | @export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = linkage }); | |
| 316 | } | |
| 317 | 309 | @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage }); |
| 318 | 310 | @export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage }); |
| 319 | 311 | @export(@import("compiler_rt/multi3.zig").__multi3, .{ .name = "__multi3", .linkage = linkage }); |
| ... | ... | @@ -337,14 +329,3 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn |
| 337 | 329 | unreachable; |
| 338 | 330 | } |
| 339 | 331 | } |
| 340 | ||
| 341 | fn __stack_chk_fail() callconv(.C) noreturn { | |
| 342 | @panic("stack smashing detected"); | |
| 343 | } | |
| 344 | ||
| 345 | var __stack_chk_guard: usize = blk: { | |
| 346 | var buf = [1]u8{0} ** @sizeOf(usize); | |
| 347 | buf[@sizeOf(usize) - 1] = 255; | |
| 348 | buf[@sizeOf(usize) - 2] = '\n'; | |
| 349 | break :blk @bitCast(usize, buf); | |
| 350 | }; |
lib/std/special/ssp.zig created+141| ... | ... | @@ -0,0 +1,141 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 6 | // | |
| 7 | // Small Zig reimplementation of gcc's libssp. | |
| 8 | // | |
| 9 | // This library implements most of the builtins required by the stack smashing | |
| 10 | // protection as implemented by gcc&clang. | |
| 11 | const std = @import("std"); | |
| 12 | const builtin = std.builtin; | |
| 13 | ||
| 14 | // Missing exports: | |
| 15 | // - __gets_chk | |
| 16 | // - __mempcpy_chk | |
| 17 | // - __snprintf_chk | |
| 18 | // - __sprintf_chk | |
| 19 | // - __stpcpy_chk | |
| 20 | // - __vsnprintf_chk | |
| 21 | // - __vsprintf_chk | |
| 22 | ||
| 23 | extern fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.C) [*:0]u8; | |
| 24 | extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8; | |
| 25 | extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8; | |
| 26 | extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8; | |
| 27 | ||
| 28 | // Avoid dragging in the runtime safety mechanisms into this .o file. | |
| 29 | pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { | |
| 30 | @setCold(true); | |
| 31 | if (@hasDecl(std.os, "abort")) | |
| 32 | std.os.abort(); | |
| 33 | while (true) {} | |
| 34 | } | |
| 35 | ||
| 36 | export fn __stack_chk_fail() callconv(.C) noreturn { | |
| 37 | @panic("stack smashing detected"); | |
| 38 | } | |
| 39 | ||
| 40 | export fn __chk_fail() callconv(.C) noreturn { | |
| 41 | @panic("buffer overflow detected"); | |
| 42 | } | |
| 43 | ||
| 44 | // Emitted when targeting some architectures (eg. i386) | |
| 45 | // XXX: This symbol should be hidden | |
| 46 | export fn __stack_chk_fail_local() callconv(.C) noreturn { | |
| 47 | __stack_chk_fail(); | |
| 48 | } | |
| 49 | ||
| 50 | // XXX: Initialize the canary with random data | |
| 51 | export var __stack_chk_guard: usize = blk: { | |
| 52 | var buf = [1]u8{0} ** @sizeOf(usize); | |
| 53 | buf[@sizeOf(usize) - 1] = 255; | |
| 54 | buf[@sizeOf(usize) - 2] = '\n'; | |
| 55 | break :blk @bitCast(usize, buf); | |
| 56 | }; | |
| 57 | ||
| 58 | export fn __strcpy_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 { | |
| 59 | @setRuntimeSafety(false); | |
| 60 | ||
| 61 | var i: usize = 0; | |
| 62 | while (i < dest_n and src[i] != 0) : (i += 1) { | |
| 63 | dest[i] = src[i]; | |
| 64 | } | |
| 65 | ||
| 66 | if (i == dest_n) __chk_fail(); | |
| 67 | ||
| 68 | dest[i] = 0; | |
| 69 | ||
| 70 | return dest; | |
| 71 | } | |
| 72 | ||
| 73 | export fn __strncpy_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 { | |
| 74 | if (dest_n < n) __chk_fail(); | |
| 75 | return strncpy(dest, src, n); | |
| 76 | } | |
| 77 | ||
| 78 | export fn __strcat_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 { | |
| 79 | @setRuntimeSafety(false); | |
| 80 | ||
| 81 | var avail = dest_n; | |
| 82 | ||
| 83 | var dest_end: usize = 0; | |
| 84 | while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) { | |
| 85 | avail -= 1; | |
| 86 | } | |
| 87 | ||
| 88 | if (avail < 1) __chk_fail(); | |
| 89 | ||
| 90 | var i: usize = 0; | |
| 91 | while (avail > 0 and src[i] != 0) : (i += 1) { | |
| 92 | dest[dest_end + i] = src[i]; | |
| 93 | avail -= 1; | |
| 94 | } | |
| 95 | ||
| 96 | if (avail < 1) __chk_fail(); | |
| 97 | ||
| 98 | dest[dest_end + i] = 0; | |
| 99 | ||
| 100 | return dest; | |
| 101 | } | |
| 102 | ||
| 103 | export fn __strncat_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 { | |
| 104 | @setRuntimeSafety(false); | |
| 105 | ||
| 106 | var avail = dest_n; | |
| 107 | ||
| 108 | var dest_end: usize = 0; | |
| 109 | while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) { | |
| 110 | avail -= 1; | |
| 111 | } | |
| 112 | ||
| 113 | if (avail < 1) __chk_fail(); | |
| 114 | ||
| 115 | var i: usize = 0; | |
| 116 | while (avail > 0 and i < n and src[i] != 0) : (i += 1) { | |
| 117 | dest[dest_end + i] = src[i]; | |
| 118 | avail -= 1; | |
| 119 | } | |
| 120 | ||
| 121 | if (avail < 1) __chk_fail(); | |
| 122 | ||
| 123 | dest[dest_end + i] = 0; | |
| 124 | ||
| 125 | return dest; | |
| 126 | } | |
| 127 | ||
| 128 | export fn __memcpy_chk(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { | |
| 129 | if (dest_n < n) __chk_fail(); | |
| 130 | return memcpy(dest, src, n); | |
| 131 | } | |
| 132 | ||
| 133 | export fn __memmove_chk(dest: ?[*]u8, src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { | |
| 134 | if (dest_n < n) __chk_fail(); | |
| 135 | return memmove(dest, src, n); | |
| 136 | } | |
| 137 | ||
| 138 | export fn __memset_chk(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 { | |
| 139 | if (dest_n < n) __chk_fail(); | |
| 140 | return memset(dest, c, n); | |
| 141 | } |
src/Compilation.zig+17| ... | ... | @@ -84,6 +84,9 @@ libcxxabi_static_lib: ?CRTFile = null, |
| 84 | 84 | /// Populated when we build the libunwind static library. A Job to build this is placed in the queue |
| 85 | 85 | /// and resolved before calling linker.flush(). |
| 86 | 86 | libunwind_static_lib: ?CRTFile = null, |
| 87 | /// Populated when we build the libssp static library. A Job to build this is placed in the queue | |
| 88 | /// and resolved before calling linker.flush(). | |
| 89 | libssp_static_lib: ?CRTFile = null, | |
| 87 | 90 | /// Populated when we build the libc static library. A Job to build this is placed in the queue |
| 88 | 91 | /// and resolved before calling linker.flush(). |
| 89 | 92 | libc_static_lib: ?CRTFile = null, |
| ... | ... | @@ -160,6 +163,7 @@ const Job = union(enum) { |
| 160 | 163 | libunwind: void, |
| 161 | 164 | libcxx: void, |
| 162 | 165 | libcxxabi: void, |
| 166 | libssp: void, | |
| 163 | 167 | /// needed when producing a dynamic library or executable |
| 164 | 168 | libcompiler_rt: void, |
| 165 | 169 | /// needed when not linking libc and using LLVM for code generation because it generates |
| ... | ... | @@ -927,6 +931,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 927 | 931 | (comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj); |
| 928 | 932 | if (needs_compiler_rt_and_c and build_options.is_stage1) { |
| 929 | 933 | try comp.work_queue.writeItem(.{ .libcompiler_rt = {} }); |
| 934 | // MinGW provides no libssp, use our own implementation. | |
| 935 | if (comp.getTarget().isMinGW()) { | |
| 936 | try comp.work_queue.writeItem(.{ .libssp = {} }); | |
| 937 | } | |
| 930 | 938 | if (!comp.bin_file.options.link_libc) { |
| 931 | 939 | try comp.work_queue.writeItem(.{ .zig_libc = {} }); |
| 932 | 940 | } |
| ... | ... | @@ -978,6 +986,9 @@ pub fn destroy(self: *Compilation) void { |
| 978 | 986 | if (self.compiler_rt_static_lib) |*crt_file| { |
| 979 | 987 | crt_file.deinit(gpa); |
| 980 | 988 | } |
| 989 | if (self.libssp_static_lib) |*crt_file| { | |
| 990 | crt_file.deinit(gpa); | |
| 991 | } | |
| 981 | 992 | if (self.libc_static_lib) |*crt_file| { |
| 982 | 993 | crt_file.deinit(gpa); |
| 983 | 994 | } |
| ... | ... | @@ -1329,6 +1340,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor |
| 1329 | 1340 | fatal("unable to build compiler_rt: {}", .{@errorName(err)}); |
| 1330 | 1341 | }; |
| 1331 | 1342 | }, |
| 1343 | .libssp => { | |
| 1344 | self.buildStaticLibFromZig("ssp.zig", &self.libssp_static_lib) catch |err| { | |
| 1345 | // TODO Expose this as a normal compile error rather than crashing here. | |
| 1346 | fatal("unable to build libssp: {}", .{@errorName(err)}); | |
| 1347 | }; | |
| 1348 | }, | |
| 1332 | 1349 | .zig_libc => { |
| 1333 | 1350 | self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| { |
| 1334 | 1351 | // TODO Expose this as a normal compile error rather than crashing here. |
src/link/Coff.zig+5-1| ... | ... | @@ -1117,11 +1117,15 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { |
| 1117 | 1117 | try argv.append(comp.libunwind_static_lib.?.full_object_path); |
| 1118 | 1118 | } |
| 1119 | 1119 | |
| 1120 | // compiler-rt and libc | |
| 1120 | // compiler-rt, libc and libssp | |
| 1121 | 1121 | if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) { |
| 1122 | 1122 | if (!self.base.options.link_libc) { |
| 1123 | 1123 | try argv.append(comp.libc_static_lib.?.full_object_path); |
| 1124 | 1124 | } |
| 1125 | // MinGW doesn't provide libssp symbols | |
| 1126 | if (target.abi.isGnu()) { | |
| 1127 | try argv.append(comp.libssp_static_lib.?.full_object_path); | |
| 1128 | } | |
| 1125 | 1129 | // MSVC compiler_rt is missing some stuff, so we build it unconditionally but |
| 1126 | 1130 | // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. |
| 1127 | 1131 | try argv.append(comp.compiler_rt_static_lib.?.full_object_path); |