| author | |
| committer | |
| log | be7cacfbbec8aed234a0316d11a9ae0e8cda0286 |
| tree | 65e070e9954eb8bfe7dbc95a4069d7f8fafe20ec |
| parent | 24ee7653184e6fbac0d05227723ddff2d716a28a |
Enabled on non-Windows systems only since it already requires stack
probes.5 files changed, 239 insertions(+), 110 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -644,6 +644,7 @@ set(ZIG_STD_FILES |
| 644 | 644 | "special/build_runner.zig" |
| 645 | 645 | "special/builtin.zig" |
| 646 | 646 | "special/compiler_rt.zig" |
| 647 | "special/compiler_rt/stack_probe.zig" | |
| 647 | 648 | "special/compiler_rt/arm/aeabi_fcmp.zig" |
| 648 | 649 | "special/compiler_rt/arm/aeabi_dcmp.zig" |
| 649 | 650 | "special/compiler_rt/addXf3.zig" |
src/codegen.cpp+11| ... | ... | @@ -399,6 +399,15 @@ static void add_uwtable_attr(CodeGen *g, LLVMValueRef fn_val) { |
| 399 | 399 | } |
| 400 | 400 | } |
| 401 | 401 | |
| 402 | static void add_probe_stack_attr(CodeGen *g, LLVMValueRef fn_val) { | |
| 403 | // Windows already emits its own stack probes | |
| 404 | if (g->zig_target->os != OsWindows && | |
| 405 | (g->zig_target->arch == ZigLLVM_x86 || | |
| 406 | g->zig_target->arch == ZigLLVM_x86_64)) { | |
| 407 | addLLVMFnAttrStr(fn_val, "probe-stack", "__zig_probe_stack"); | |
| 408 | } | |
| 409 | } | |
| 410 | ||
| 402 | 411 | static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) { |
| 403 | 412 | switch (id) { |
| 404 | 413 | case GlobalLinkageIdInternal: |
| ... | ... | @@ -587,6 +596,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 587 | 596 | addLLVMFnAttr(fn_table_entry->llvm_value, "sspstrong"); |
| 588 | 597 | addLLVMFnAttrStr(fn_table_entry->llvm_value, "stack-protector-buffer-size", "4"); |
| 589 | 598 | } |
| 599 | ||
| 600 | add_probe_stack_attr(g, fn_table_entry->llvm_value); | |
| 590 | 601 | } |
| 591 | 602 | } else { |
| 592 | 603 | maybe_import_dll(g, fn_table_entry->llvm_value, linkage); |
src/main.cpp+6| ... | ... | @@ -18,6 +18,12 @@ |
| 18 | 18 | |
| 19 | 19 | #include <stdio.h> |
| 20 | 20 | |
| 21 | // Define this symbol here so that we can link with the zig objects during the | |
| 22 | // compiler bootstrap phase | |
| 23 | extern "C" { | |
| 24 | void __zig_probe_stack(void) { } | |
| 25 | } | |
| 26 | ||
| 21 | 27 | static int print_error_usage(const char *arg0) { |
| 22 | 28 | fprintf(stderr, "See `%s --help` for detailed usage information\n", arg0); |
| 23 | 29 | return EXIT_FAILURE; |
std/special/compiler_rt.zig+15-110| ... | ... | @@ -1,10 +1,17 @@ |
| 1 | 1 | const builtin = @import("builtin"); |
| 2 | 2 | const is_test = builtin.is_test; |
| 3 | 3 | |
| 4 | const stack_probe = @import("compiler_rt/stack_probe.zig"); | |
| 5 | ||
| 4 | 6 | comptime { |
| 5 | 7 | const linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Weak; |
| 6 | 8 | const strong_linkage = if (is_test) builtin.GlobalLinkage.Internal else builtin.GlobalLinkage.Strong; |
| 7 | 9 | |
| 10 | switch (builtin.arch) { | |
| 11 | .i386, .x86_64 => @export("__zig_probe_stack", @import("compiler_rt/stack_probe.zig").zig_probe_stack, linkage), | |
| 12 | else => { } | |
| 13 | } | |
| 14 | ||
| 8 | 15 | @export("__lesf2", @import("compiler_rt/comparesf2.zig").__lesf2, linkage); |
| 9 | 16 | @export("__ledf2", @import("compiler_rt/comparedf2.zig").__ledf2, linkage); |
| 10 | 17 | @export("__letf2", @import("compiler_rt/comparetf2.zig").__letf2, linkage); |
| ... | ... | @@ -191,20 +198,20 @@ comptime { |
| 191 | 198 | @export("__aeabi_dcmpun", @import("compiler_rt/comparedf2.zig").__unorddf2, linkage); |
| 192 | 199 | } |
| 193 | 200 | if (builtin.os == builtin.Os.windows) { |
| 201 | if (!builtin.link_libc) { | |
| 202 | @export("_chkstk", @import("compiler_rt/stack_probe.zig")._chkstk, strong_linkage); | |
| 203 | @export("__chkstk", @import("compiler_rt/stack_probe.zig").__chkstk, strong_linkage); | |
| 204 | @export("___chkstk", @import("compiler_rt/stack_probe.zig").___chkstk, strong_linkage); | |
| 205 | @export("__chkstk_ms", @import("compiler_rt/stack_probe.zig").__chkstk_ms, strong_linkage); | |
| 206 | @export("___chkstk_ms", @import("compiler_rt/stack_probe.zig").___chkstk_ms, strong_linkage); | |
| 207 | } | |
| 208 | ||
| 194 | 209 | switch (builtin.arch) { |
| 195 | 210 | builtin.Arch.i386 => { |
| 196 | if (!builtin.link_libc) { | |
| 197 | @export("_chkstk", _chkstk, strong_linkage); | |
| 198 | @export("__chkstk_ms", __chkstk_ms, linkage); | |
| 199 | } | |
| 200 | 211 | @export("_aulldiv", @import("compiler_rt/aulldiv.zig")._aulldiv, strong_linkage); |
| 201 | 212 | @export("_aullrem", @import("compiler_rt/aullrem.zig")._aullrem, strong_linkage); |
| 202 | 213 | }, |
| 203 | 214 | builtin.Arch.x86_64 => { |
| 204 | if (!builtin.link_libc) { | |
| 205 | @export("__chkstk", __chkstk, strong_linkage); | |
| 206 | @export("___chkstk_ms", ___chkstk_ms, linkage); | |
| 207 | } | |
| 208 | 215 | // The "ti" functions must use @Vector(2, u64) parameter types to adhere to the ABI |
| 209 | 216 | // that LLVM expects compiler-rt to have. |
| 210 | 217 | @export("__divti3", @import("compiler_rt/divti3.zig").__divti3_windows_x86_64, linkage); |
| ... | ... | @@ -492,108 +499,6 @@ nakedcc fn __aeabi_memcmp() noreturn { |
| 492 | 499 | unreachable; |
| 493 | 500 | } |
| 494 | 501 | |
| 495 | // _chkstk (_alloca) routine - probe stack between %esp and (%esp-%eax) in 4k increments, | |
| 496 | // then decrement %esp by %eax. Preserves all registers except %esp and flags. | |
| 497 | // This routine is windows specific | |
| 498 | // http://msdn.microsoft.com/en-us/library/ms648426.aspx | |
| 499 | nakedcc fn _chkstk() align(4) void { | |
| 500 | @setRuntimeSafety(false); | |
| 501 | ||
| 502 | asm volatile ( | |
| 503 | \\ push %%ecx | |
| 504 | \\ push %%eax | |
| 505 | \\ cmp $0x1000,%%eax | |
| 506 | \\ lea 12(%%esp),%%ecx | |
| 507 | \\ jb 1f | |
| 508 | \\ 2: | |
| 509 | \\ sub $0x1000,%%ecx | |
| 510 | \\ test %%ecx,(%%ecx) | |
| 511 | \\ sub $0x1000,%%eax | |
| 512 | \\ cmp $0x1000,%%eax | |
| 513 | \\ ja 2b | |
| 514 | \\ 1: | |
| 515 | \\ sub %%eax,%%ecx | |
| 516 | \\ test %%ecx,(%%ecx) | |
| 517 | \\ pop %%eax | |
| 518 | \\ pop %%ecx | |
| 519 | \\ ret | |
| 520 | ); | |
| 521 | } | |
| 522 | ||
| 523 | nakedcc fn __chkstk() align(4) void { | |
| 524 | @setRuntimeSafety(false); | |
| 525 | ||
| 526 | asm volatile ( | |
| 527 | \\ push %%rcx | |
| 528 | \\ push %%rax | |
| 529 | \\ cmp $0x1000,%%rax | |
| 530 | \\ lea 24(%%rsp),%%rcx | |
| 531 | \\ jb 1f | |
| 532 | \\2: | |
| 533 | \\ sub $0x1000,%%rcx | |
| 534 | \\ test %%rcx,(%%rcx) | |
| 535 | \\ sub $0x1000,%%rax | |
| 536 | \\ cmp $0x1000,%%rax | |
| 537 | \\ ja 2b | |
| 538 | \\1: | |
| 539 | \\ sub %%rax,%%rcx | |
| 540 | \\ test %%rcx,(%%rcx) | |
| 541 | \\ pop %%rax | |
| 542 | \\ pop %%rcx | |
| 543 | \\ ret | |
| 544 | ); | |
| 545 | } | |
| 546 | ||
| 547 | // _chkstk routine | |
| 548 | // This routine is windows specific | |
| 549 | // http://msdn.microsoft.com/en-us/library/ms648426.aspx | |
| 550 | nakedcc fn __chkstk_ms() align(4) void { | |
| 551 | @setRuntimeSafety(false); | |
| 552 | ||
| 553 | asm volatile ( | |
| 554 | \\ push %%ecx | |
| 555 | \\ push %%eax | |
| 556 | \\ cmp $0x1000,%%eax | |
| 557 | \\ lea 12(%%esp),%%ecx | |
| 558 | \\ jb 1f | |
| 559 | \\ 2: | |
| 560 | \\ sub $0x1000,%%ecx | |
| 561 | \\ test %%ecx,(%%ecx) | |
| 562 | \\ sub $0x1000,%%eax | |
| 563 | \\ cmp $0x1000,%%eax | |
| 564 | \\ ja 2b | |
| 565 | \\ 1: | |
| 566 | \\ sub %%eax,%%ecx | |
| 567 | \\ test %%ecx,(%%ecx) | |
| 568 | \\ pop %%eax | |
| 569 | \\ pop %%ecx | |
| 570 | \\ ret | |
| 571 | ); | |
| 572 | } | |
| 573 | ||
| 574 | nakedcc fn ___chkstk_ms() align(4) void { | |
| 575 | @setRuntimeSafety(false); | |
| 576 | ||
| 577 | asm volatile ( | |
| 578 | \\ push %%rcx | |
| 579 | \\ push %%rax | |
| 580 | \\ cmp $0x1000,%%rax | |
| 581 | \\ lea 24(%%rsp),%%rcx | |
| 582 | \\ jb 1f | |
| 583 | \\2: | |
| 584 | \\ sub $0x1000,%%rcx | |
| 585 | \\ test %%rcx,(%%rcx) | |
| 586 | \\ sub $0x1000,%%rax | |
| 587 | \\ cmp $0x1000,%%rax | |
| 588 | \\ ja 2b | |
| 589 | \\1: | |
| 590 | \\ sub %%rax,%%rcx | |
| 591 | \\ test %%rcx,(%%rcx) | |
| 592 | \\ pop %%rax | |
| 593 | \\ pop %%rcx | |
| 594 | \\ ret | |
| 595 | ); | |
| 596 | } | |
| 597 | 502 | |
| 598 | 503 | extern fn __divmodsi4(a: i32, b: i32, rem: *i32) i32 { |
| 599 | 504 | @setRuntimeSafety(is_test); |
std/special/compiler_rt/stack_probe.zig created+206| ... | ... | @@ -0,0 +1,206 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | ||
| 3 | // Zig's own stack-probe routine (available only on x86 and x86_64) | |
| 4 | pub nakedcc fn zig_probe_stack() void { | |
| 5 | @setRuntimeSafety(false); | |
| 6 | ||
| 7 | // Versions of the Linux kernel before 5.1 treat any access below SP as | |
| 8 | // invalid so let's update it on the go, otherwise we'll get a segfault | |
| 9 | // instead of triggering the stack growth. | |
| 10 | ||
| 11 | switch (builtin.arch) { | |
| 12 | .x86_64 => { | |
| 13 | // %rax = probe length, %rsp = stack pointer | |
| 14 | asm volatile ( | |
| 15 | \\ push %%rcx | |
| 16 | \\ mov %%rax, %%rcx | |
| 17 | \\ cmp $0x1000,%%rcx | |
| 18 | \\ jb 2f | |
| 19 | \\ 1: | |
| 20 | \\ sub $0x1000,%%rsp | |
| 21 | \\ orl $0,16(%%rsp) | |
| 22 | \\ sub $0x1000,%%rcx | |
| 23 | \\ cmp $0x1000,%%rcx | |
| 24 | \\ ja 1b | |
| 25 | \\ 2: | |
| 26 | \\ sub %%rcx, %%rsp | |
| 27 | \\ orl $0,16(%%rsp) | |
| 28 | \\ add %%rax,%%rsp | |
| 29 | \\ pop %%rcx | |
| 30 | \\ ret | |
| 31 | ); | |
| 32 | }, | |
| 33 | .i386 => { | |
| 34 | // %eax = probe length, %esp = stack pointer | |
| 35 | asm volatile ( | |
| 36 | \\ push %%ecx | |
| 37 | \\ mov %%eax, %%ecx | |
| 38 | \\ cmp $0x1000,%%ecx | |
| 39 | \\ jb 2f | |
| 40 | \\ 1: | |
| 41 | \\ sub $0x1000,%%esp | |
| 42 | \\ orl $0,8(%%esp) | |
| 43 | \\ sub $0x1000,%%ecx | |
| 44 | \\ cmp $0x1000,%%ecx | |
| 45 | \\ ja 1b | |
| 46 | \\ 2: | |
| 47 | \\ sub %%ecx, %%esp | |
| 48 | \\ orl $0,8(%%esp) | |
| 49 | \\ add %%eax,%%esp | |
| 50 | \\ pop %%ecx | |
| 51 | \\ ret | |
| 52 | ); | |
| 53 | }, | |
| 54 | else => { } | |
| 55 | } | |
| 56 | ||
| 57 | unreachable; | |
| 58 | } | |
| 59 | ||
| 60 | fn win_probe_stack_only() void { | |
| 61 | @setRuntimeSafety(false); | |
| 62 | ||
| 63 | switch (builtin.arch) { | |
| 64 | .x86_64 => { | |
| 65 | asm volatile ( | |
| 66 | \\ push %%rcx | |
| 67 | \\ push %%rax | |
| 68 | \\ cmp $0x1000,%%rax | |
| 69 | \\ lea 24(%%rsp),%%rcx | |
| 70 | \\ jb 1f | |
| 71 | \\ 2: | |
| 72 | \\ sub $0x1000,%%rcx | |
| 73 | \\ test %%rcx,(%%rcx) | |
| 74 | \\ sub $0x1000,%%rax | |
| 75 | \\ cmp $0x1000,%%rax | |
| 76 | \\ ja 2b | |
| 77 | \\ 1: | |
| 78 | \\ sub %%rax,%%rcx | |
| 79 | \\ test %%rcx,(%%rcx) | |
| 80 | \\ pop %%rax | |
| 81 | \\ pop %%rcx | |
| 82 | \\ ret | |
| 83 | ); | |
| 84 | }, | |
| 85 | .i386 => { | |
| 86 | asm volatile ( | |
| 87 | \\ push %%ecx | |
| 88 | \\ push %%eax | |
| 89 | \\ cmp $0x1000,%%eax | |
| 90 | \\ lea 12(%%esp),%%ecx | |
| 91 | \\ jb 1f | |
| 92 | \\ 2: | |
| 93 | \\ sub $0x1000,%%ecx | |
| 94 | \\ test %%ecx,(%%ecx) | |
| 95 | \\ sub $0x1000,%%eax | |
| 96 | \\ cmp $0x1000,%%eax | |
| 97 | \\ ja 2b | |
| 98 | \\ 1: | |
| 99 | \\ sub %%eax,%%ecx | |
| 100 | \\ test %%ecx,(%%ecx) | |
| 101 | \\ pop %%eax | |
| 102 | \\ pop %%ecx | |
| 103 | \\ ret | |
| 104 | ); | |
| 105 | }, | |
| 106 | else => { } | |
| 107 | } | |
| 108 | ||
| 109 | unreachable; | |
| 110 | } | |
| 111 | ||
| 112 | fn win_probe_stack_adjust_sp() void { | |
| 113 | @setRuntimeSafety(false); | |
| 114 | ||
| 115 | switch (builtin.arch) { | |
| 116 | .x86_64 => { | |
| 117 | asm volatile ( | |
| 118 | \\ push %%rcx | |
| 119 | \\ cmp $0x1000,%%rax | |
| 120 | \\ lea 16(%%rsp),%%rcx | |
| 121 | \\ jb 1f | |
| 122 | \\ 2: | |
| 123 | \\ sub $0x1000,%%rcx | |
| 124 | \\ test %%rcx,(%%rcx) | |
| 125 | \\ sub $0x1000,%%rax | |
| 126 | \\ cmp $0x1000,%%rax | |
| 127 | \\ ja 2b | |
| 128 | \\ 1: | |
| 129 | \\ sub %%rax,%%rcx | |
| 130 | \\ test %%rcx,(%%rcx) | |
| 131 | \\ | |
| 132 | \\ lea 8(%%rsp),%%rax | |
| 133 | \\ mov %%rcx,%%rsp | |
| 134 | \\ mov -8(%%rax),%%rcx | |
| 135 | \\ push (%%rax) | |
| 136 | \\ sub %%rsp,%%rax | |
| 137 | \\ ret | |
| 138 | ); | |
| 139 | }, | |
| 140 | .i386 => { | |
| 141 | asm volatile ( | |
| 142 | \\ push %%ecx | |
| 143 | \\ cmp $0x1000,%%eax | |
| 144 | \\ lea 8(%%esp),%%ecx | |
| 145 | \\ jb 1f | |
| 146 | \\ 2: | |
| 147 | \\ sub $0x1000,%%ecx | |
| 148 | \\ test %%ecx,(%%ecx) | |
| 149 | \\ sub $0x1000,%%eax | |
| 150 | \\ cmp $0x1000,%%eax | |
| 151 | \\ ja 2b | |
| 152 | \\ 1: | |
| 153 | \\ sub %%eax,%%ecx | |
| 154 | \\ test %%ecx,(%%ecx) | |
| 155 | \\ | |
| 156 | \\ lea 4(%%esp),%%eax | |
| 157 | \\ mov %%ecx,%%esp | |
| 158 | \\ mov -4(%%eax),%%ecx | |
| 159 | \\ push (%%eax) | |
| 160 | \\ sub %%esp,%%eax | |
| 161 | \\ ret | |
| 162 | ); | |
| 163 | }, | |
| 164 | else => { }, | |
| 165 | } | |
| 166 | ||
| 167 | unreachable; | |
| 168 | } | |
| 169 | ||
| 170 | // Windows has a multitude of stack-probing functions with similar names and | |
| 171 | // slightly different behaviours: some behave as alloca() and update the stack | |
| 172 | // pointer after probing the stack, other do not. | |
| 173 | // | |
| 174 | // Function name | Adjusts the SP? | | |
| 175 | // | x86 | x86_64 | | |
| 176 | // ---------------------------------------- | |
| 177 | // _chkstk (_alloca) | yes | yes | | |
| 178 | // __chkstk | yes | no | | |
| 179 | // __chkstk_ms | no | no | | |
| 180 | // ___chkstk (__alloca) | yes | yes | | |
| 181 | // ___chkstk_ms | no | no | | |
| 182 | ||
| 183 | pub nakedcc fn _chkstk() void { | |
| 184 | @setRuntimeSafety(false); | |
| 185 | @inlineCall(win_probe_stack_adjust_sp); | |
| 186 | } | |
| 187 | pub nakedcc fn __chkstk() void { | |
| 188 | @setRuntimeSafety(false); | |
| 189 | switch (builtin.arch) { | |
| 190 | .i386 => @inlineCall(win_probe_stack_adjust_sp), | |
| 191 | .x86_64 => @inlineCall(win_probe_stack_only), | |
| 192 | else => unreachable | |
| 193 | } | |
| 194 | } | |
| 195 | pub nakedcc fn ___chkstk() void { | |
| 196 | @setRuntimeSafety(false); | |
| 197 | @inlineCall(win_probe_stack_adjust_sp); | |
| 198 | } | |
| 199 | pub nakedcc fn __chkstk_ms() void { | |
| 200 | @setRuntimeSafety(false); | |
| 201 | @inlineCall(win_probe_stack_only); | |
| 202 | } | |
| 203 | pub nakedcc fn ___chkstk_ms() void { | |
| 204 | @setRuntimeSafety(false); | |
| 205 | @inlineCall(win_probe_stack_only); | |
| 206 | } |