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
This commit is contained in:
parent
2aff27d922
commit
d44486b274
@ -35,6 +35,10 @@ comptime {
|
|||||||
@export(strncmp, .{ .name = "strncmp", .linkage = .Strong });
|
@export(strncmp, .{ .name = "strncmp", .linkage = .Strong });
|
||||||
@export(strerror, .{ .name = "strerror", .linkage = .Strong });
|
@export(strerror, .{ .name = "strerror", .linkage = .Strong });
|
||||||
@export(strlen, .{ .name = "strlen", .linkage = .Strong });
|
@export(strlen, .{ .name = "strlen", .linkage = .Strong });
|
||||||
|
@export(strcpy, .{ .name = "strcpy", .linkage = .Strong });
|
||||||
|
@export(strncpy, .{ .name = "strncpy", .linkage = .Strong });
|
||||||
|
@export(strcat, .{ .name = "strcat", .linkage = .Strong });
|
||||||
|
@export(strncat, .{ .name = "strncat", .linkage = .Strong });
|
||||||
} else if (is_msvc) {
|
} else if (is_msvc) {
|
||||||
@export(_fltused, .{ .name = "_fltused", .linkage = .Strong });
|
@export(_fltused, .{ .name = "_fltused", .linkage = .Strong });
|
||||||
}
|
}
|
||||||
@ -47,6 +51,90 @@ fn wasm_start() callconv(.C) void {
|
|||||||
_ = main(0, undefined);
|
_ = main(0, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn strcpy(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 {
|
||||||
|
var i: usize = 0;
|
||||||
|
while (src[i] != 0) : (i += 1) {
|
||||||
|
dest[i] = src[i];
|
||||||
|
}
|
||||||
|
dest[i] = 0;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "strcpy" {
|
||||||
|
var s1: [9:0]u8 = undefined;
|
||||||
|
|
||||||
|
s1[0] = 0;
|
||||||
|
_ = strcpy(&s1, "foobarbaz");
|
||||||
|
std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.C) [*:0]u8 {
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < n and src[i] != 0) : (i += 1) {
|
||||||
|
dest[i] = src[i];
|
||||||
|
}
|
||||||
|
while (i < n) : (i += 1) {
|
||||||
|
dest[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "strncpy" {
|
||||||
|
var s1: [9:0]u8 = undefined;
|
||||||
|
|
||||||
|
s1[0] = 0;
|
||||||
|
_ = strncpy(&s1, "foobarbaz", 9);
|
||||||
|
std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strcat(dest: [*:0]u8, src: [*:0]const u8) callconv(.C) [*:0]u8 {
|
||||||
|
var dest_end: usize = 0;
|
||||||
|
while (dest[dest_end] != 0) : (dest_end += 1) {}
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (src[i] != 0) : (i += 1) {
|
||||||
|
dest[dest_end + i] = src[i];
|
||||||
|
}
|
||||||
|
dest[dest_end + i] = 0;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "strcat" {
|
||||||
|
var s1: [9:0]u8 = undefined;
|
||||||
|
|
||||||
|
s1[0] = 0;
|
||||||
|
_ = strcat(&s1, "foo");
|
||||||
|
_ = strcat(&s1, "bar");
|
||||||
|
_ = strcat(&s1, "baz");
|
||||||
|
std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strncat(dest: [*:0]u8, src: [*:0]const u8, avail: usize) callconv(.C) [*:0]u8 {
|
||||||
|
var dest_end: usize = 0;
|
||||||
|
while (dest[dest_end] != 0) : (dest_end += 1) {}
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < avail and src[i] != 0) : (i += 1) {
|
||||||
|
dest[dest_end + i] = src[i];
|
||||||
|
}
|
||||||
|
dest[dest_end + i] = 0;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "strncat" {
|
||||||
|
var s1: [9:0]u8 = undefined;
|
||||||
|
|
||||||
|
s1[0] = 0;
|
||||||
|
_ = strncat(&s1, "foo1111", 3);
|
||||||
|
_ = strncat(&s1, "bar1111", 3);
|
||||||
|
_ = strncat(&s1, "baz1111", 3);
|
||||||
|
std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1));
|
||||||
|
}
|
||||||
|
|
||||||
fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {
|
fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int {
|
||||||
return std.cstr.cmp(s1, s2);
|
return std.cstr.cmp(s1, s2);
|
||||||
}
|
}
|
||||||
@ -92,7 +180,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn
|
|||||||
while (true) {}
|
while (true) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 {
|
export fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8 {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
|
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
@ -102,7 +190,13 @@ export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]u8 {
|
export fn __memset(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
|
||||||
|
if (dest_n < n)
|
||||||
|
@panic("buffer overflow");
|
||||||
|
return memset(dest, c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
|
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
@ -112,7 +206,7 @@ export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*]
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 {
|
export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8 {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
|
|
||||||
if (@ptrToInt(dest) < @ptrToInt(src)) {
|
if (@ptrToInt(dest) < @ptrToInt(src)) {
|
||||||
@ -131,7 +225,7 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) isize {
|
export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) isize {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
|
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
@ -146,17 +240,17 @@ export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) isize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "test_memcmp" {
|
test "test_memcmp" {
|
||||||
const base_arr = []u8{ 1, 1, 1 };
|
const base_arr = &[_]u8{ 1, 1, 1 };
|
||||||
const arr1 = []u8{ 1, 1, 1 };
|
const arr1 = &[_]u8{ 1, 1, 1 };
|
||||||
const arr2 = []u8{ 1, 0, 1 };
|
const arr2 = &[_]u8{ 1, 0, 1 };
|
||||||
const arr3 = []u8{ 1, 2, 1 };
|
const arr3 = &[_]u8{ 1, 2, 1 };
|
||||||
|
|
||||||
std.testing.expect(memcmp(base_arr[0..].ptr, arr1[0..].ptr, base_arr.len) == 0);
|
std.testing.expect(memcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
|
||||||
std.testing.expect(memcmp(base_arr[0..].ptr, arr2[0..].ptr, base_arr.len) > 0);
|
std.testing.expect(memcmp(base_arr[0..], arr2[0..], base_arr.len) > 0);
|
||||||
std.testing.expect(memcmp(base_arr[0..].ptr, arr3[0..].ptr, base_arr.len) < 0);
|
std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) isize {
|
export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) isize {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
|
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
@ -170,30 +264,21 @@ export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) i
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "test_bcmp" {
|
test "test_bcmp" {
|
||||||
const base_arr = []u8{ 1, 1, 1 };
|
const base_arr = &[_]u8{ 1, 1, 1 };
|
||||||
const arr1 = []u8{ 1, 1, 1 };
|
const arr1 = &[_]u8{ 1, 1, 1 };
|
||||||
const arr2 = []u8{ 1, 0, 1 };
|
const arr2 = &[_]u8{ 1, 0, 1 };
|
||||||
const arr3 = []u8{ 1, 2, 1 };
|
const arr3 = &[_]u8{ 1, 2, 1 };
|
||||||
|
|
||||||
std.testing.expect(bcmp(base_arr[0..].ptr, arr1[0..].ptr, base_arr.len) == 0);
|
std.testing.expect(bcmp(base_arr[0..], arr1[0..], base_arr.len) == 0);
|
||||||
std.testing.expect(bcmp(base_arr[0..].ptr, arr2[0..].ptr, base_arr.len) != 0);
|
std.testing.expect(bcmp(base_arr[0..], arr2[0..], base_arr.len) != 0);
|
||||||
std.testing.expect(bcmp(base_arr[0..].ptr, arr3[0..].ptr, base_arr.len) != 0);
|
std.testing.expect(bcmp(base_arr[0..], arr3[0..], base_arr.len) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
if (builtin.mode != builtin.Mode.ReleaseFast and
|
|
||||||
builtin.mode != builtin.Mode.ReleaseSmall and
|
|
||||||
builtin.os.tag != .windows)
|
|
||||||
{
|
|
||||||
@export(__stack_chk_fail, .{ .name = "__stack_chk_fail" });
|
|
||||||
}
|
|
||||||
if (builtin.os.tag == .linux) {
|
if (builtin.os.tag == .linux) {
|
||||||
@export(clone, .{ .name = "clone" });
|
@export(clone, .{ .name = "clone" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn __stack_chk_fail() callconv(.C) noreturn {
|
|
||||||
@panic("stack smashing detected");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO we should be able to put this directly in std/linux/x86_64.zig but
|
// TODO we should be able to put this directly in std/linux/x86_64.zig but
|
||||||
// it causes a segfault in release mode. this is a workaround of calling it
|
// it causes a segfault in release mode. this is a workaround of calling it
|
||||||
@ -416,7 +501,6 @@ fn clone() callconv(.Naked) void {
|
|||||||
\\ # move syscall number into r0
|
\\ # move syscall number into r0
|
||||||
\\ li 0, 120
|
\\ li 0, 120
|
||||||
\\ sc
|
\\ sc
|
||||||
|
|
||||||
\\ # check for syscall error
|
\\ # check for syscall error
|
||||||
\\ bns+ 1f # jump to label 1 if no summary overflow.
|
\\ bns+ 1f # jump to label 1 if no summary overflow.
|
||||||
\\ #else
|
\\ #else
|
||||||
@ -424,10 +508,8 @@ fn clone() callconv(.Naked) void {
|
|||||||
\\1:
|
\\1:
|
||||||
\\ # compare sc result with 0
|
\\ # compare sc result with 0
|
||||||
\\ cmpwi cr7, 3, 0
|
\\ cmpwi cr7, 3, 0
|
||||||
|
|
||||||
\\ # if not 0, jump to end
|
\\ # if not 0, jump to end
|
||||||
\\ bne cr7, 2f
|
\\ bne cr7, 2f
|
||||||
|
|
||||||
\\ #else: we're the child
|
\\ #else: we're the child
|
||||||
\\ #call funcptr: move arg (d) into r3
|
\\ #call funcptr: move arg (d) into r3
|
||||||
\\ mr 3, 31
|
\\ mr 3, 31
|
||||||
@ -438,13 +520,11 @@ fn clone() callconv(.Naked) void {
|
|||||||
\\ # mov SYS_exit into r0 (the exit param is already in r3)
|
\\ # mov SYS_exit into r0 (the exit param is already in r3)
|
||||||
\\ li 0, 1
|
\\ li 0, 1
|
||||||
\\ sc
|
\\ sc
|
||||||
|
|
||||||
\\2:
|
\\2:
|
||||||
\\ # restore stack
|
\\ # restore stack
|
||||||
\\ lwz 30, 0(1)
|
\\ lwz 30, 0(1)
|
||||||
\\ lwz 31, 4(1)
|
\\ lwz 31, 4(1)
|
||||||
\\ addi 1, 1, 16
|
\\ addi 1, 1, 16
|
||||||
|
|
||||||
\\ blr
|
\\ blr
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -284,11 +284,6 @@ comptime {
|
|||||||
@export(@import("compiler_rt/stack_probe.zig").__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage });
|
@export(@import("compiler_rt/stack_probe.zig").__chkstk, .{ .name = "__chkstk", .linkage = strong_linkage });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_mingw) {
|
|
||||||
@export(__stack_chk_fail, .{ .name = "__stack_chk_fail", .linkage = strong_linkage });
|
|
||||||
@export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = strong_linkage });
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (builtin.arch) {
|
switch (builtin.arch) {
|
||||||
.i386 => {
|
.i386 => {
|
||||||
@export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
|
@export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
|
||||||
@ -311,9 +306,6 @@ comptime {
|
|||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (std.Target.current.isGnuLibC() and builtin.link_libc) {
|
|
||||||
@export(__stack_chk_guard, .{ .name = "__stack_chk_guard", .linkage = linkage });
|
|
||||||
}
|
|
||||||
@export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
|
@export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
|
||||||
@export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage });
|
@export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage });
|
||||||
@export(@import("compiler_rt/multi3.zig").__multi3, .{ .name = "__multi3", .linkage = linkage });
|
@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
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __stack_chk_fail() callconv(.C) noreturn {
|
|
||||||
@panic("stack smashing detected");
|
|
||||||
}
|
|
||||||
|
|
||||||
var __stack_chk_guard: usize = blk: {
|
|
||||||
var buf = [1]u8{0} ** @sizeOf(usize);
|
|
||||||
buf[@sizeOf(usize) - 1] = 255;
|
|
||||||
buf[@sizeOf(usize) - 2] = '\n';
|
|
||||||
break :blk @bitCast(usize, buf);
|
|
||||||
};
|
|
||||||
|
141
lib/std/special/ssp.zig
Normal file
141
lib/std/special/ssp.zig
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright (c) 2015-2020 Zig Contributors
|
||||||
|
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||||
|
// The MIT license requires this copyright notice to be included in all copies
|
||||||
|
// and substantial portions of the software.
|
||||||
|
//
|
||||||
|
// Small Zig reimplementation of gcc's libssp.
|
||||||
|
//
|
||||||
|
// This library implements most of the builtins required by the stack smashing
|
||||||
|
// protection as implemented by gcc&clang.
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = std.builtin;
|
||||||
|
|
||||||
|
// Missing exports:
|
||||||
|
// - __gets_chk
|
||||||
|
// - __mempcpy_chk
|
||||||
|
// - __snprintf_chk
|
||||||
|
// - __sprintf_chk
|
||||||
|
// - __stpcpy_chk
|
||||||
|
// - __vsnprintf_chk
|
||||||
|
// - __vsprintf_chk
|
||||||
|
|
||||||
|
extern fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.C) [*:0]u8;
|
||||||
|
extern fn memset(dest: ?[*]u8, c: u8, n: usize) callconv(.C) ?[*]u8;
|
||||||
|
extern fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8;
|
||||||
|
extern fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8;
|
||||||
|
|
||||||
|
// Avoid dragging in the runtime safety mechanisms into this .o file.
|
||||||
|
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
|
||||||
|
@setCold(true);
|
||||||
|
if (@hasDecl(std.os, "abort"))
|
||||||
|
std.os.abort();
|
||||||
|
while (true) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn __stack_chk_fail() callconv(.C) noreturn {
|
||||||
|
@panic("stack smashing detected");
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn __chk_fail() callconv(.C) noreturn {
|
||||||
|
@panic("buffer overflow detected");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emitted when targeting some architectures (eg. i386)
|
||||||
|
// XXX: This symbol should be hidden
|
||||||
|
export fn __stack_chk_fail_local() callconv(.C) noreturn {
|
||||||
|
__stack_chk_fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: Initialize the canary with random data
|
||||||
|
export var __stack_chk_guard: usize = blk: {
|
||||||
|
var buf = [1]u8{0} ** @sizeOf(usize);
|
||||||
|
buf[@sizeOf(usize) - 1] = 255;
|
||||||
|
buf[@sizeOf(usize) - 2] = '\n';
|
||||||
|
break :blk @bitCast(usize, buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
export fn __strcpy_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 {
|
||||||
|
@setRuntimeSafety(false);
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < dest_n and src[i] != 0) : (i += 1) {
|
||||||
|
dest[i] = src[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == dest_n) __chk_fail();
|
||||||
|
|
||||||
|
dest[i] = 0;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn __strncpy_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 {
|
||||||
|
if (dest_n < n) __chk_fail();
|
||||||
|
return strncpy(dest, src, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn __strcat_chk(dest: [*:0]u8, src: [*:0]const u8, dest_n: usize) callconv(.C) [*:0]u8 {
|
||||||
|
@setRuntimeSafety(false);
|
||||||
|
|
||||||
|
var avail = dest_n;
|
||||||
|
|
||||||
|
var dest_end: usize = 0;
|
||||||
|
while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) {
|
||||||
|
avail -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avail < 1) __chk_fail();
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (avail > 0 and src[i] != 0) : (i += 1) {
|
||||||
|
dest[dest_end + i] = src[i];
|
||||||
|
avail -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avail < 1) __chk_fail();
|
||||||
|
|
||||||
|
dest[dest_end + i] = 0;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn __strncat_chk(dest: [*:0]u8, src: [*:0]const u8, n: usize, dest_n: usize) callconv(.C) [*:0]u8 {
|
||||||
|
@setRuntimeSafety(false);
|
||||||
|
|
||||||
|
var avail = dest_n;
|
||||||
|
|
||||||
|
var dest_end: usize = 0;
|
||||||
|
while (avail > 0 and dest[dest_end] != 0) : (dest_end += 1) {
|
||||||
|
avail -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avail < 1) __chk_fail();
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (avail > 0 and i < n and src[i] != 0) : (i += 1) {
|
||||||
|
dest[dest_end + i] = src[i];
|
||||||
|
avail -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avail < 1) __chk_fail();
|
||||||
|
|
||||||
|
dest[dest_end + i] = 0;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn __memcpy_chk(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
|
||||||
|
if (dest_n < n) __chk_fail();
|
||||||
|
return memcpy(dest, src, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn __memmove_chk(dest: ?[*]u8, src: ?[*]const u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
|
||||||
|
if (dest_n < n) __chk_fail();
|
||||||
|
return memmove(dest, src, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn __memset_chk(dest: ?[*]u8, c: u8, n: usize, dest_n: usize) callconv(.C) ?[*]u8 {
|
||||||
|
if (dest_n < n) __chk_fail();
|
||||||
|
return memset(dest, c, n);
|
||||||
|
}
|
@ -84,6 +84,9 @@ libcxxabi_static_lib: ?CRTFile = null,
|
|||||||
/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
|
/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
|
||||||
/// and resolved before calling linker.flush().
|
/// and resolved before calling linker.flush().
|
||||||
libunwind_static_lib: ?CRTFile = null,
|
libunwind_static_lib: ?CRTFile = null,
|
||||||
|
/// Populated when we build the libssp static library. A Job to build this is placed in the queue
|
||||||
|
/// and resolved before calling linker.flush().
|
||||||
|
libssp_static_lib: ?CRTFile = null,
|
||||||
/// Populated when we build the libc static library. A Job to build this is placed in the queue
|
/// Populated when we build the libc static library. A Job to build this is placed in the queue
|
||||||
/// and resolved before calling linker.flush().
|
/// and resolved before calling linker.flush().
|
||||||
libc_static_lib: ?CRTFile = null,
|
libc_static_lib: ?CRTFile = null,
|
||||||
@ -160,6 +163,7 @@ const Job = union(enum) {
|
|||||||
libunwind: void,
|
libunwind: void,
|
||||||
libcxx: void,
|
libcxx: void,
|
||||||
libcxxabi: void,
|
libcxxabi: void,
|
||||||
|
libssp: void,
|
||||||
/// needed when producing a dynamic library or executable
|
/// needed when producing a dynamic library or executable
|
||||||
libcompiler_rt: void,
|
libcompiler_rt: void,
|
||||||
/// needed when not linking libc and using LLVM for code generation because it generates
|
/// 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 {
|
|||||||
(comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj);
|
(comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj);
|
||||||
if (needs_compiler_rt_and_c and build_options.is_stage1) {
|
if (needs_compiler_rt_and_c and build_options.is_stage1) {
|
||||||
try comp.work_queue.writeItem(.{ .libcompiler_rt = {} });
|
try comp.work_queue.writeItem(.{ .libcompiler_rt = {} });
|
||||||
|
// MinGW provides no libssp, use our own implementation.
|
||||||
|
if (comp.getTarget().isMinGW()) {
|
||||||
|
try comp.work_queue.writeItem(.{ .libssp = {} });
|
||||||
|
}
|
||||||
if (!comp.bin_file.options.link_libc) {
|
if (!comp.bin_file.options.link_libc) {
|
||||||
try comp.work_queue.writeItem(.{ .zig_libc = {} });
|
try comp.work_queue.writeItem(.{ .zig_libc = {} });
|
||||||
}
|
}
|
||||||
@ -978,6 +986,9 @@ pub fn destroy(self: *Compilation) void {
|
|||||||
if (self.compiler_rt_static_lib) |*crt_file| {
|
if (self.compiler_rt_static_lib) |*crt_file| {
|
||||||
crt_file.deinit(gpa);
|
crt_file.deinit(gpa);
|
||||||
}
|
}
|
||||||
|
if (self.libssp_static_lib) |*crt_file| {
|
||||||
|
crt_file.deinit(gpa);
|
||||||
|
}
|
||||||
if (self.libc_static_lib) |*crt_file| {
|
if (self.libc_static_lib) |*crt_file| {
|
||||||
crt_file.deinit(gpa);
|
crt_file.deinit(gpa);
|
||||||
}
|
}
|
||||||
@ -1329,6 +1340,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
|
|||||||
fatal("unable to build compiler_rt: {}", .{@errorName(err)});
|
fatal("unable to build compiler_rt: {}", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
.libssp => {
|
||||||
|
self.buildStaticLibFromZig("ssp.zig", &self.libssp_static_lib) catch |err| {
|
||||||
|
// TODO Expose this as a normal compile error rather than crashing here.
|
||||||
|
fatal("unable to build libssp: {}", .{@errorName(err)});
|
||||||
|
};
|
||||||
|
},
|
||||||
.zig_libc => {
|
.zig_libc => {
|
||||||
self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| {
|
self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| {
|
||||||
// TODO Expose this as a normal compile error rather than crashing here.
|
// TODO Expose this as a normal compile error rather than crashing here.
|
||||||
|
@ -1117,11 +1117,15 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
|
|||||||
try argv.append(comp.libunwind_static_lib.?.full_object_path);
|
try argv.append(comp.libunwind_static_lib.?.full_object_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// compiler-rt and libc
|
// compiler-rt, libc and libssp
|
||||||
if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {
|
if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {
|
||||||
if (!self.base.options.link_libc) {
|
if (!self.base.options.link_libc) {
|
||||||
try argv.append(comp.libc_static_lib.?.full_object_path);
|
try argv.append(comp.libc_static_lib.?.full_object_path);
|
||||||
}
|
}
|
||||||
|
// MinGW doesn't provide libssp symbols
|
||||||
|
if (target.abi.isGnu()) {
|
||||||
|
try argv.append(comp.libssp_static_lib.?.full_object_path);
|
||||||
|
}
|
||||||
// MSVC compiler_rt is missing some stuff, so we build it unconditionally but
|
// MSVC compiler_rt is missing some stuff, so we build it unconditionally but
|
||||||
// and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
|
// and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
|
||||||
try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
|
try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user