From f1bd02e6f46821415d96f54f6a3258159ba5a9c5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 2 Oct 2017 22:00:42 -0400 Subject: [PATCH 1/3] add @setAlignStack builtin --- src/all_types.hpp | 10 ++++++ src/codegen.cpp | 11 +++--- src/ir.cpp | 71 +++++++++++++++++++++++++++++++++++++++ src/ir_print.cpp | 9 +++++ src/link.cpp | 2 +- std/special/bootstrap.zig | 9 +++++ test/cases/align.zig | 18 ++++++++++ test/compile_errors.zig | 33 ++++++++++++++++++ 8 files changed, 158 insertions(+), 5 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 05df479beb..bbb4f43497 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1191,6 +1191,8 @@ struct FnTableEntry { Buf *section_name; AstNode *set_global_linkage_node; GlobalLinkageId linkage; + AstNode *set_alignstack_node; + uint32_t alignstack_value; }; uint32_t fn_table_entry_hash(FnTableEntry*); @@ -1254,6 +1256,7 @@ enum BuiltinFnId { BuiltinFnIdSetEvalBranchQuota, BuiltinFnIdAlignCast, BuiltinFnIdOpaqueType, + BuiltinFnIdSetAlignStack, }; struct BuiltinFnEntry { @@ -1860,6 +1863,7 @@ enum IrInstructionId { IrInstructionIdPtrTypeOf, IrInstructionIdAlignCast, IrInstructionIdOpaqueType, + IrInstructionIdSetAlignStack, }; struct IrInstruction { @@ -2654,6 +2658,12 @@ struct IrInstructionOpaqueType { IrInstruction base; }; +struct IrInstructionSetAlignStack { + IrInstruction base; + + IrInstruction *align_bytes; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index 18d19e39f0..6a0e7e12f4 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -410,6 +410,9 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { addLLVMFnAttr(fn_table_entry->llvm_value, "noinline"); break; case FnInlineAuto: + if (fn_table_entry->alignstack_value != 0) { + addLLVMFnAttr(fn_table_entry->llvm_value, "noinline"); + } break; } @@ -452,10 +455,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { } } - if (g->zig_target.os == ZigLLVM_Win32 && g->zig_target.arch.arch == ZigLLVM_x86_64 && - fn_type->data.fn.fn_type_id.cc != CallingConventionNaked) - { - addLLVMFnAttrInt(fn_table_entry->llvm_value, "alignstack", 16); + if (fn_table_entry->alignstack_value != 0) { + addLLVMFnAttrInt(fn_table_entry->llvm_value, "alignstack", fn_table_entry->alignstack_value); } addLLVMFnAttr(fn_table_entry->llvm_value, "nounwind"); @@ -3379,6 +3380,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdSetEvalBranchQuota: case IrInstructionIdPtrTypeOf: case IrInstructionIdOpaqueType: + case IrInstructionIdSetAlignStack: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); @@ -4784,6 +4786,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1); create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2); create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); + create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index 422c40b678..570783872f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -563,6 +563,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) { return IrInstructionIdOpaqueType; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionSetAlignStack *) { + return IrInstructionIdSetAlignStack; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -2248,6 +2252,17 @@ static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } +static IrInstruction *ir_build_set_align_stack(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *align_bytes) +{ + IrInstructionSetAlignStack *instruction = ir_build_instruction(irb, scope, source_node); + instruction->align_bytes = align_bytes; + + ir_ref_instruction(align_bytes, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { return nullptr; } @@ -2970,6 +2985,13 @@ static IrInstruction *ir_instruction_opaquetype_get_dep(IrInstructionOpaqueType return nullptr; } +static IrInstruction *ir_instruction_setalignstack_get_dep(IrInstructionSetAlignStack *instruction, size_t index) { + switch (index) { + case 0: return instruction->align_bytes; + default: return nullptr; + } +} + static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -3170,6 +3192,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_aligncast_get_dep((IrInstructionAlignCast *) instruction, index); case IrInstructionIdOpaqueType: return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index); + case IrInstructionIdSetAlignStack: + return ir_instruction_setalignstack_get_dep((IrInstructionSetAlignStack *) instruction, index); } zig_unreachable(); } @@ -4596,6 +4620,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } case BuiltinFnIdOpaqueType: return ir_build_opaque_type(irb, scope, node); + case BuiltinFnIdSetAlignStack: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + return ir_build_set_align_stack(irb, scope, node, arg0_value); + } } zig_unreachable(); } @@ -15264,6 +15297,41 @@ static TypeTableEntry *ir_analyze_instruction_opaque_type(IrAnalyze *ira, IrInst return ira->codegen->builtin_types.entry_type; } +static TypeTableEntry *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, IrInstructionSetAlignStack *instruction) { + uint32_t align_bytes; + IrInstruction *align_bytes_inst = instruction->align_bytes->other; + if (!ir_resolve_align(ira, align_bytes_inst, &align_bytes)) + return ira->codegen->builtin_types.entry_invalid; + + FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); + if (fn_entry == nullptr) { + ir_add_error(ira, &instruction->base, buf_sprintf("@setAlignStack outside function")); + return ira->codegen->builtin_types.entry_invalid; + } + if (fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionNaked) { + ir_add_error(ira, &instruction->base, buf_sprintf("@setAlignStack in naked function")); + return ira->codegen->builtin_types.entry_invalid; + } + + if (fn_entry->fn_inline == FnInlineAlways) { + ir_add_error(ira, &instruction->base, buf_sprintf("@setAlignStack in inline function")); + return ira->codegen->builtin_types.entry_invalid; + } + + if (fn_entry->set_alignstack_node != nullptr) { + ErrorMsg *msg = ir_add_error_node(ira, instruction->base.source_node, + buf_sprintf("alignstack set twice")); + add_error_note(ira->codegen, msg, fn_entry->set_alignstack_node, buf_sprintf("first set here")); + return ira->codegen->builtin_types.entry_invalid; + } + + fn_entry->set_alignstack_node = instruction->base.source_node; + fn_entry->alignstack_value = align_bytes; + + ir_build_const_from(ira, &instruction->base); + return ira->codegen->builtin_types.entry_void; +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -15452,6 +15520,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction); case IrInstructionIdOpaqueType: return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction); + case IrInstructionIdSetAlignStack: + return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction); } zig_unreachable(); } @@ -15564,6 +15634,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPanic: case IrInstructionIdSetEvalBranchQuota: case IrInstructionIdPtrTypeOf: + case IrInstructionIdSetAlignStack: return true; case IrInstructionIdPhi: case IrInstructionIdUnOp: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index fccf11038a..63ccd76ef0 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -948,6 +948,12 @@ static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruct fprintf(irp->f, "@OpaqueType()"); } +static void ir_print_set_align_stack(IrPrint *irp, IrInstructionSetAlignStack *instruction) { + fprintf(irp->f, "@setAlignStack("); + ir_print_other_instruction(irp, instruction->align_bytes); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1247,6 +1253,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdOpaqueType: ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction); break; + case IrInstructionIdSetAlignStack: + ir_print_set_align_stack(irp, (IrInstructionSetAlignStack *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/src/link.cpp b/src/link.cpp index 75ec651942..bd17ff1ea4 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -846,7 +846,7 @@ void codegen_link(CodeGen *g, const char *out_file) { buf_resize(&lj.out_file, 0); } - if (g->verbose) { + if (g->verbose || g->verbose_ir) { fprintf(stderr, "\nOptimization:\n"); fprintf(stderr, "---------------\n"); LLVMDumpModule(g->module); diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index d2554fd8df..3067406431 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -19,6 +19,14 @@ export nakedcc fn _start() -> noreturn { } if (is_windows) { + if (builtin.arch == builtin.Arch.x86_64) { + // Align the stack pointer to 16 bytes. + asm volatile ( + \\ and $0xfffffffffffffff0,%%rsp + \\ sub $0x10,%%rsp + :::"rsp" + ); + } windowsCallMainAndExit() } @@ -35,6 +43,7 @@ export nakedcc fn _start() -> noreturn { } fn windowsCallMainAndExit() -> noreturn { + @setAlignStack(16); std.debug.user_main_fn = root.main; root.main() %% std.os.windows.ExitProcess(1); std.os.windows.ExitProcess(0); diff --git a/test/cases/align.zig b/test/cases/align.zig index c655b1b593..98d307964c 100644 --- a/test/cases/align.zig +++ b/test/cases/align.zig @@ -1,4 +1,5 @@ const assert = @import("std").debug.assert; +const builtin = @import("builtin"); var foo: u8 align(4) = 100; @@ -180,3 +181,20 @@ fn testIndex(smaller: &align(2) u32, index: usize, comptime T: type) { fn testIndex2(ptr: &align(4) u8, index: usize, comptime T: type) { assert(@typeOf(&ptr[index]) == T); } + + +test "alignstack" { + fnWithAlignedStack(); +} + +fn fnWithAlignedStack() { + @setAlignStack(1024); + const stack_address = if (builtin.arch == builtin.Arch.x86_64) { + asm volatile ("" :[rsp] "={rsp}"(-> usize)) + } else if (builtin.arch == builtin.Arch.i386) { + asm volatile ("" :[esp] "={esp}"(-> usize)) + } else { + return; + }; + assert(stack_address % 1024 == 0); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index fc74cc1bf0..cbde0e9b99 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2153,4 +2153,37 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} , ".tmp_source.zig:14:17: error: use of undeclared identifier 'HeaderValue'"); + + cases.add("@setAlignStack outside function", + \\comptime { + \\ @setAlignStack(16); + \\} + , + ".tmp_source.zig:2:5: error: @setAlignStack outside function"); + + cases.add("@setAlignStack in naked function", + \\export nakedcc fn entry() { + \\ @setAlignStack(16); + \\} + , + ".tmp_source.zig:2:5: error: @setAlignStack in naked function"); + + cases.add("@setAlignStack in inline function", + \\export fn entry() { + \\ foo(); + \\} + \\inline fn foo() { + \\ @setAlignStack(16); + \\} + , + ".tmp_source.zig:5:5: error: @setAlignStack in inline function"); + + cases.add("@setAlignStack set twice", + \\export fn entry() { + \\ @setAlignStack(16); + \\ @setAlignStack(16); + \\} + , + ".tmp_source.zig:3:5: error: alignstack set twice", + ".tmp_source.zig:2:5: note: first set here"); } From b5054625093ef22b3f228199b6fbf70e1c50b703 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Oct 2017 00:27:14 -0400 Subject: [PATCH 2/3] replace __chkstk function with a stub that does not crash Closes #508 See #302 --- src/codegen.cpp | 17 +++++------------ src/link.cpp | 2 +- std/special/bootstrap.zig | 24 +++++++++--------------- std/special/compiler_rt/index.zig | 27 ++++++--------------------- 4 files changed, 21 insertions(+), 49 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 6a0e7e12f4..efcf6ea3e3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -867,7 +867,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { addLLVMFnAttr(fn_val, "noreturn"); addLLVMFnAttr(fn_val, "cold"); LLVMSetLinkage(fn_val, LLVMInternalLinkage); - LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv); + LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); addLLVMFnAttr(fn_val, "nounwind"); if (g->build_mode == BuildModeDebug) { ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); @@ -924,7 +924,8 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); - ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, LLVMFastCallConv, false, ""); + ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified), + false, ""); LLVMBuildUnreachable(g->builder); } @@ -5007,16 +5008,8 @@ static void init(CodeGen *g) { const char *target_specific_cpu_args; const char *target_specific_features; if (g->is_native_target) { - // LLVM creates invalid binaries on Windows sometimes. - // See https://github.com/zig-lang/zig/issues/508 - // As a workaround we do not use target native features on Windows. - if (g->zig_target.os == ZigLLVM_Win32) { - target_specific_cpu_args = ""; - target_specific_features = ""; - } else { - target_specific_cpu_args = ZigLLVMGetHostCPUName(); - target_specific_features = ZigLLVMGetNativeFeatures(); - } + target_specific_cpu_args = ZigLLVMGetHostCPUName(); + target_specific_features = ZigLLVMGetNativeFeatures(); } else { target_specific_cpu_args = ""; target_specific_features = ""; diff --git a/src/link.cpp b/src/link.cpp index bd17ff1ea4..35b350df0f 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -423,7 +423,7 @@ static void construct_linker_job_coff(LinkJob *lj) { if (g->have_winmain) { lj->args.append("-ENTRY:WinMain"); } else { - lj->args.append("-ENTRY:_start"); + lj->args.append("-ENTRY:WinMainCRTStartup"); } } diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 3067406431..fea062712b 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -5,12 +5,13 @@ const root = @import("@root"); const std = @import("std"); const builtin = @import("builtin"); +const is_windows = builtin.os == builtin.Os.windows; const want_main_symbol = builtin.link_libc; -const want_start_symbol = !want_main_symbol; +const want_start_symbol = !want_main_symbol and !is_windows; +const want_WinMainCRTStartup = is_windows and !builtin.link_libc; var argc_ptr: &usize = undefined; -const is_windows = builtin.os == builtin.Os.windows; export nakedcc fn _start() -> noreturn { if (!want_start_symbol) { @@ -18,18 +19,6 @@ export nakedcc fn _start() -> noreturn { unreachable; } - if (is_windows) { - if (builtin.arch == builtin.Arch.x86_64) { - // Align the stack pointer to 16 bytes. - asm volatile ( - \\ and $0xfffffffffffffff0,%%rsp - \\ sub $0x10,%%rsp - :::"rsp" - ); - } - windowsCallMainAndExit() - } - switch (builtin.arch) { builtin.Arch.x86_64 => { argc_ptr = asm("lea (%%rsp), %[argc]": [argc] "=r" (-> &usize)); @@ -42,8 +31,13 @@ export nakedcc fn _start() -> noreturn { posixCallMainAndExit() } -fn windowsCallMainAndExit() -> noreturn { +export fn WinMainCRTStartup() -> noreturn { + if (!want_WinMainCRTStartup) { + @setGlobalLinkage(WinMainCRTStartup, builtin.GlobalLinkage.Internal); + unreachable; + } @setAlignStack(16); + std.debug.user_main_fn = root.main; root.main() %% std.os.windows.ExitProcess(1); std.os.windows.ExitProcess(0); diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index 36ad997120..f27e3069f0 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -155,32 +155,17 @@ export nakedcc fn _chkstk() align(4) { @setGlobalLinkage(_chkstk, builtin.GlobalLinkage.Internal); } -export nakedcc fn __chkstk() align(4) { +// TODO The implementation from compiler-rt causes crashes and +// the implementation from disassembled ntdll seems to depend on +// thread local storage. So we have given up this safety check +// and simply have `ret`. +export nakedcc fn __chkstk() align(8) { @setDebugSafety(this, false); if (win64_nocrt) { @setGlobalLinkage(__chkstk, strong_linkage); asm volatile ( - \\ push %%rcx - \\ cmp $0x1000,%%rax - \\ lea 16(%%rsp),%%rcx // rsp before calling this routine -> rcx - \\ jb 1f - \\ 2: - \\ sub $0x1000,%%rcx - \\ test %%rcx,(%%rcx) - \\ sub $0x1000,%%rax - \\ cmp $0x1000,%%rax - \\ ja 2b - \\ 1: - \\ sub %%rax,%%rcx - \\ test %%rcx,(%%rcx) - \\ - \\ lea 8(%%rsp),%%rax // load pointer to the return address into rax - \\ mov %%rcx,%%rsp // install the new top of stack pointer into rsp - \\ mov -8(%%rax),%%rcx // restore rcx - \\ push (%%rax) // push return address onto the stack - \\ sub %%rsp,%%rax // restore the original value in rax - \\ ret + \\ ret ); unreachable; } From 6a0c4289974dbe27d8980425e7e6061078ecf896 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Oct 2017 00:57:02 -0400 Subject: [PATCH 3/3] use __chkstk_ms compiler-rt functions for __chkstk I had to revert the target native features thing because there is still some incorrect behavior with f128. Reopens #508 partially reverts b5054625093ef22b3f228199b6fbf70e1c50b703 See #302 --- src/codegen.cpp | 12 ++++++++++-- std/special/compiler_rt/index.zig | 31 ++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index efcf6ea3e3..5889ba316a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5008,8 +5008,16 @@ static void init(CodeGen *g) { const char *target_specific_cpu_args; const char *target_specific_features; if (g->is_native_target) { - target_specific_cpu_args = ZigLLVMGetHostCPUName(); - target_specific_features = ZigLLVMGetNativeFeatures(); + // LLVM creates invalid binaries on Windows sometimes. + // See https://github.com/zig-lang/zig/issues/508 + // As a workaround we do not use target native features on Windows. + if (g->zig_target.os == ZigLLVM_Win32) { + target_specific_cpu_args = ""; + target_specific_features = ""; + } else { + target_specific_cpu_args = ZigLLVMGetHostCPUName(); + target_specific_features = ZigLLVMGetNativeFeatures(); + } } else { target_specific_cpu_args = ""; target_specific_features = ""; diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index f27e3069f0..4a4d71fde9 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -129,8 +129,9 @@ export nakedcc fn _chkstk() align(4) { @setGlobalLinkage(_chkstk, strong_linkage); asm volatile ( \\ push %%ecx + \\ push %%eax \\ cmp $0x1000,%%eax - \\ lea 8(%%esp),%%ecx // esp before calling this routine -> ecx + \\ lea 12(%%esp),%%ecx \\ jb 1f \\ 2: \\ sub $0x1000,%%ecx @@ -141,12 +142,8 @@ export nakedcc fn _chkstk() align(4) { \\ 1: \\ sub %%eax,%%ecx \\ test %%ecx,(%%ecx) - \\ - \\ lea 4(%%esp),%%eax // load pointer to the return address into eax - \\ mov %%ecx,%%esp // install the new top of stack pointer into esp - \\ mov -4(%%eax),%%ecx // restore ecx - \\ push (%%eax) // push return address onto the stack - \\ sub %%esp,%%eax // restore the original value in eax + \\ pop %%eax + \\ pop %%ecx \\ ret ); unreachable; @@ -159,13 +156,29 @@ export nakedcc fn _chkstk() align(4) { // the implementation from disassembled ntdll seems to depend on // thread local storage. So we have given up this safety check // and simply have `ret`. -export nakedcc fn __chkstk() align(8) { +export nakedcc fn __chkstk() align(4) { @setDebugSafety(this, false); if (win64_nocrt) { @setGlobalLinkage(__chkstk, strong_linkage); asm volatile ( - \\ ret + \\ push %%rcx + \\ push %%rax + \\ cmp $0x1000,%%rax + \\ lea 24(%%rsp),%%rcx + \\ jb 1f + \\2: + \\ sub $0x1000,%%rcx + \\ test %%rcx,(%%rcx) + \\ sub $0x1000,%%rax + \\ cmp $0x1000,%%rax + \\ ja 2b + \\1: + \\ sub %%rax,%%rcx + \\ test %%rcx,(%%rcx) + \\ pop %%rax + \\ pop %%rcx + \\ ret ); unreachable; }