authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-10-02 16:48:18+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-16 21:22:14-04:00
logd44486b274a916823fcf6045a6400ef51e07d544
treec12a3a3923b644d219f815630941073d99d31889
parent2aff27d92247eed3b64ffc68da8fae9e5994ea0b

std: Add libssp implementation for GNU/Windows targets

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 #6492

5 files changed, 276 insertions(+), 53 deletions(-)

lib/std/special/c.zig+113-33
...@@ -35,6 +35,10 @@ comptime {...@@ -35,6 +35,10 @@ comptime {
35 @export(strncmp, .{ .name = "strncmp", .linkage = .Strong });35 @export(strncmp, .{ .name = "strncmp", .linkage = .Strong });
36 @export(strerror, .{ .name = "strerror", .linkage = .Strong });36 @export(strerror, .{ .name = "strerror", .linkage = .Strong });
37 @export(strlen, .{ .name = "strlen", .linkage = .Strong });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 } else if (is_msvc) {42 } else if (is_msvc) {
39 @export(_fltused, .{ .name = "_fltused", .linkage = .Strong });43 @export(_fltused, .{ .name = "_fltused", .linkage = .Strong });
40 }44 }
...@@ -47,6 +51,90 @@ fn wasm_start() callconv(.C) void {...@@ -47,6 +51,90 @@ fn wasm_start() callconv(.C) void {
47 _ = main(0, undefined);51 _ = main(0, undefined);
48}52}
4953
54fn 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
64test "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
72fn 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
84test "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
92fn 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
105test "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
115fn 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
128test "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
50fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {138fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {
51 return std.cstr.cmp(s1, s2);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,7 +180,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn
92 while (true) {}180 while (true) {}
93}181}
94182
95export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 {183export fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8 {
96 @setRuntimeSafety(false);184 @setRuntimeSafety(false);
97185
98 var index: usize = 0;186 var index: usize = 0;
...@@ -102,7 +190,13 @@ export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 {...@@ -102,7 +190,13 @@ export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 {
102 return dest;190 return dest;
103}191}
104192
105export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]u8 {193export 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
199export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 {
106 @setRuntimeSafety(false);200 @setRuntimeSafety(false);
107201
108 var index: usize = 0;202 var index: usize = 0;
...@@ -112,7 +206,7 @@ export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]...@@ -112,7 +206,7 @@ export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]
112 return dest;206 return dest;
113}207}
114208
115export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 {209export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 {
116 @setRuntimeSafety(false);210 @setRuntimeSafety(false);
117211
118 if (@ptrToInt(dest) < @ptrToInt(src)) {212 if (@ptrToInt(dest) < @ptrToInt(src)) {
...@@ -131,7 +225,7 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 {...@@ -131,7 +225,7 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 {
131 return dest;225 return dest;
132}226}
133227
134export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) isize {228export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) isize {
135 @setRuntimeSafety(false);229 @setRuntimeSafety(false);
136230
137 var index: usize = 0;231 var index: usize = 0;
...@@ -146,17 +240,17 @@ export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) isize {...@@ -146,17 +240,17 @@ export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) isize {
146}240}
147241
148test "test_memcmp" {242test "test_memcmp" {
149 const base_arr = []u8{ 1, 1, 1 };243 const base_arr = &[_]u8{ 1, 1, 1 };
150 const arr1 = []u8{ 1, 1, 1 };244 const arr1 = &[_]u8{ 1, 1, 1 };
151 const arr2 = []u8{ 1, 0, 1 };245 const arr2 = &[_]u8{ 1, 0, 1 };
152 const arr3 = []u8{ 1, 2, 1 };246 const arr3 = &[_]u8{ 1, 2, 1 };
153247
154 std.testing.expect(memcmp(base_arr[0..].ptr, arr1[0..].ptr, base_arr.len) == 0);248 std.testing.expect(memcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
155 std.testing.expect(memcmp(base_arr[0..].ptr, arr2[0..].ptr, base_arr.len) > 0);249 std.testing.expect(memcmp(base_arr[0..], arr2[0..], base_arr.len) > 0);
156 std.testing.expect(memcmp(base_arr[0..].ptr, arr3[0..].ptr, base_arr.len) < 0);250 std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0);
157}251}
158252
159export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) isize {253export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) isize {
160 @setRuntimeSafety(false);254 @setRuntimeSafety(false);
161255
162 var index: usize = 0;256 var index: usize = 0;
...@@ -170,30 +264,21 @@ export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) i...@@ -170,30 +264,21 @@ export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) i
170}264}
171265
172test "test_bcmp" {266test "test_bcmp" {
173 const base_arr = []u8{ 1, 1, 1 };267 const base_arr = &[_]u8{ 1, 1, 1 };
174 const arr1 = []u8{ 1, 1, 1 };268 const arr1 = &[_]u8{ 1, 1, 1 };
175 const arr2 = []u8{ 1, 0, 1 };269 const arr2 = &[_]u8{ 1, 0, 1 };
176 const arr3 = []u8{ 1, 2, 1 };270 const arr3 = &[_]u8{ 1, 2, 1 };
177271
178 std.testing.expect(bcmp(base_arr[0..].ptr, arr1[0..].ptr, base_arr.len) == 0);272 std.testing.expect(bcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
179 std.testing.expect(bcmp(base_arr[0..].ptr, arr2[0..].ptr, base_arr.len) != 0);273 std.testing.expect(bcmp(base_arr[0..], arr2[0..], base_arr.len) != 0);
180 std.testing.expect(bcmp(base_arr[0..].ptr, arr3[0..].ptr, base_arr.len) != 0);274 std.testing.expect(bcmp(base_arr[0..], arr3[0..], base_arr.len) != 0);
181}275}
182276
183comptime {277comptime {
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 if (builtin.os.tag == .linux) {278 if (builtin.os.tag == .linux) {
191 @export(clone, .{ .name = "clone" });279 @export(clone, .{ .name = "clone" });
192 }280 }
193}281}
194fn __stack_chk_fail() callconv(.C) noreturn {
195 @panic("stack smashing detected");
196}
197282
198// TODO we should be able to put this directly in std/linux/x86_64.zig but283// TODO we should be able to put this directly in std/linux/x86_64.zig but
199// it causes a segfault in release mode. this is a workaround of calling it284// it causes a segfault in release mode. this is a workaround of calling it
...@@ -416,7 +501,6 @@ fn clone() callconv(.Naked) void {...@@ -416,7 +501,6 @@ fn clone() callconv(.Naked) void {
416 \\ # move syscall number into r0501 \\ # move syscall number into r0
417 \\ li 0, 120502 \\ li 0, 120
418 \\ sc503 \\ sc
419
420 \\ # check for syscall error504 \\ # check for syscall error
421 \\ bns+ 1f # jump to label 1 if no summary overflow.505 \\ bns+ 1f # jump to label 1 if no summary overflow.
422 \\ #else506 \\ #else
...@@ -424,10 +508,8 @@ fn clone() callconv(.Naked) void {...@@ -424,10 +508,8 @@ fn clone() callconv(.Naked) void {
424 \\1:508 \\1:
425 \\ # compare sc result with 0509 \\ # compare sc result with 0
426 \\ cmpwi cr7, 3, 0510 \\ cmpwi cr7, 3, 0
427
428 \\ # if not 0, jump to end511 \\ # if not 0, jump to end
429 \\ bne cr7, 2f512 \\ bne cr7, 2f
430
431 \\ #else: we're the child513 \\ #else: we're the child
432 \\ #call funcptr: move arg (d) into r3514 \\ #call funcptr: move arg (d) into r3
433 \\ mr 3, 31515 \\ mr 3, 31
...@@ -438,13 +520,11 @@ fn clone() callconv(.Naked) void {...@@ -438,13 +520,11 @@ fn clone() callconv(.Naked) void {
438 \\ # mov SYS_exit into r0 (the exit param is already in r3)520 \\ # mov SYS_exit into r0 (the exit param is already in r3)
439 \\ li 0, 1521 \\ li 0, 1
440 \\ sc522 \\ sc
441
442 \\2:523 \\2:
443 \\ # restore stack524 \\ # restore stack
444 \\ lwz 30, 0(1)525 \\ lwz 30, 0(1)
445 \\ lwz 31, 4(1)526 \\ lwz 31, 4(1)
446 \\ addi 1, 1, 16527 \\ addi 1, 1, 16
447
448 \\ blr528 \\ blr
449 );529 );
450 },530 },
lib/std/special/compiler_rt.zig-19
...@@ -284,11 +284,6 @@ comptime {...@@ -284,11 +284,6 @@ comptime {
284 @export(@import("compiler_rt/stack_probe.zig").__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage });284 @export(@import("compiler_rt/stack_probe.zig").__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage });
285 }285 }
286286
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 switch (builtin.arch) {287 switch (builtin.arch) {
293 .i386 => {288 .i386 => {
294 @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });289 @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
...@@ -311,9 +306,6 @@ comptime {...@@ -311,9 +306,6 @@ comptime {
311 else => {},306 else => {},
312 }307 }
313 } else {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 @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });309 @export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
318 @export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage });310 @export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage });
319 @export(@import("compiler_rt/multi3.zig").__multi3, .{ .name = "__multi3", .linkage = linkage });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,14 +329,3 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn
337 unreachable;329 unreachable;
338 }330 }
339}331}
340
341fn __stack_chk_fail() callconv(.C) noreturn {
342 @panic("stack smashing detected");
343}
344
345var __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.
11const std = @import("std");
12const 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
23extern fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.C) [*:0]u8;
24extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8;
25extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8;
26extern 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.
29pub 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
36export fn __stack_chk_fail() callconv(.C) noreturn {
37 @panic("stack smashing detected");
38}
39
40export 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
46export fn __stack_chk_fail_local() callconv(.C) noreturn {
47 __stack_chk_fail();
48}
49
50// XXX: Initialize the canary with random data
51export 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
58export 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
73export 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
78export 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
103export 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
128export 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
133export 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
138export 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,6 +84,9 @@ libcxxabi_static_lib: ?CRTFile = null,
84/// Populated when we build the libunwind static library. A Job to build this is placed in the queue84/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
85/// and resolved before calling linker.flush().85/// and resolved before calling linker.flush().
86libunwind_static_lib: ?CRTFile = null,86libunwind_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().
89libssp_static_lib: ?CRTFile = null,
87/// Populated when we build the libc static library. A Job to build this is placed in the queue90/// Populated when we build the libc static library. A Job to build this is placed in the queue
88/// and resolved before calling linker.flush().91/// and resolved before calling linker.flush().
89libc_static_lib: ?CRTFile = null,92libc_static_lib: ?CRTFile = null,
...@@ -160,6 +163,7 @@ const Job = union(enum) {...@@ -160,6 +163,7 @@ const Job = union(enum) {
160 libunwind: void,163 libunwind: void,
161 libcxx: void,164 libcxx: void,
162 libcxxabi: void,165 libcxxabi: void,
166 libssp: void,
163 /// needed when producing a dynamic library or executable167 /// needed when producing a dynamic library or executable
164 libcompiler_rt: void,168 libcompiler_rt: void,
165 /// needed when not linking libc and using LLVM for code generation because it generates169 /// 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,6 +931,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
927 (comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj);931 (comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj);
928 if (needs_compiler_rt_and_c and build_options.is_stage1) {932 if (needs_compiler_rt_and_c and build_options.is_stage1) {
929 try comp.work_queue.writeItem(.{ .libcompiler_rt = {} });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 if (!comp.bin_file.options.link_libc) {938 if (!comp.bin_file.options.link_libc) {
931 try comp.work_queue.writeItem(.{ .zig_libc = {} });939 try comp.work_queue.writeItem(.{ .zig_libc = {} });
932 }940 }
...@@ -978,6 +986,9 @@ pub fn destroy(self: *Compilation) void {...@@ -978,6 +986,9 @@ pub fn destroy(self: *Compilation) void {
978 if (self.compiler_rt_static_lib) |*crt_file| {986 if (self.compiler_rt_static_lib) |*crt_file| {
979 crt_file.deinit(gpa);987 crt_file.deinit(gpa);
980 }988 }
989 if (self.libssp_static_lib) |*crt_file| {
990 crt_file.deinit(gpa);
991 }
981 if (self.libc_static_lib) |*crt_file| {992 if (self.libc_static_lib) |*crt_file| {
982 crt_file.deinit(gpa);993 crt_file.deinit(gpa);
983 }994 }
...@@ -1329,6 +1340,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -1329,6 +1340,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
1329 fatal("unable to build compiler_rt: {}", .{@errorName(err)});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 .zig_libc => {1349 .zig_libc => {
1333 self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| {1350 self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| {
1334 // TODO Expose this as a normal compile error rather than crashing here.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,11 +1117,15 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
1117 try argv.append(comp.libunwind_static_lib.?.full_object_path);1117 try argv.append(comp.libunwind_static_lib.?.full_object_path);
1118 }1118 }
11191119
1120 // compiler-rt and libc1120 // compiler-rt, libc and libssp
1121 if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {1121 if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {
1122 if (!self.base.options.link_libc) {1122 if (!self.base.options.link_libc) {
1123 try argv.append(comp.libc_static_lib.?.full_object_path);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 // MSVC compiler_rt is missing some stuff, so we build it unconditionally but1129 // MSVC compiler_rt is missing some stuff, so we build it unconditionally but
1126 // and rely on weak linkage to allow MSVC compiler_rt functions to override ours.1130 // and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
1127 try argv.append(comp.compiler_rt_static_lib.?.full_object_path);1131 try argv.append(comp.compiler_rt_static_lib.?.full_object_path);