diff --git a/Cargo.toml b/Cargo.toml index 1436d9b4d..3bfd25389 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ test = false core = { version = "1.0.0", optional = true, package = 'rustc-std-workspace-core' } [build-dependencies] -cc = { optional = true, version = "1.0" } +cc = { version = "1.0" } [dev-dependencies] panic-handler = { path = 'crates/panic-handler' } @@ -42,7 +42,7 @@ default = ["compiler-builtins"] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics -c = ["cc"] +c = [] # Flag this library as the unstable compiler-builtins lib compiler-builtins = [] diff --git a/build.rs b/build.rs index c714bc15d..aebea0811 100644 --- a/build.rs +++ b/build.rs @@ -28,6 +28,22 @@ fn main() { println!("cargo:rustc-cfg=feature=\"mem\""); } + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap(); + if target_os != "windows" { + let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + if target_arch == "x86_64" { + let cfg = &mut cc::Build::new(); + cfg.file(&"src/probestack_x86_64.S"); + cfg.compile("libcompiler-probestack.a"); + } + + if target_arch == "x86" { + let cfg = &mut cc::Build::new(); + cfg.file(&"src/probestack_x86.S"); + cfg.compile("libcompiler-probestack.a"); + } + } + // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the // target triple. This is usually correct for our built-in targets but can break in presence of // custom targets, which can have arbitrary names. diff --git a/src/probestack.rs b/src/probestack.rs index f9284e814..9126f5161 100644 --- a/src/probestack.rs +++ b/src/probestack.rs @@ -41,88 +41,4 @@ //! probes on any other architecture like ARM or PowerPC64. LLVM I'm sure would //! be more than welcome to accept such a change! -#![cfg(not(windows))] // Windows already has builtins to do this - -#[naked] -#[no_mangle] -#[cfg(all(target_arch = "x86_64", not(feature = "mangled-names")))] -pub unsafe extern "C" fn __rust_probestack() { - // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, - // ensuring that if any pages are unmapped we'll make a page fault. - // - // The ABI here is that the stack frame size is located in `%eax`. Upon - // return we're not supposed to modify `%esp` or `%eax`. - asm!(" - mov %rax,%r11 // duplicate %rax as we're clobbering %r11 - - // Main loop, taken in one page increments. We're decrementing rsp by - // a page each time until there's less than a page remaining. We're - // guaranteed that this function isn't called unless there's more than a - // page needed. - // - // Note that we're also testing against `8(%rsp)` to account for the 8 - // bytes pushed on the stack orginally with our return address. Using - // `8(%rsp)` simulates us testing the stack pointer in the caller's - // context. - - // It's usually called when %rax >= 0x1000, but that's not always true. - // Dynamic stack allocation, which is needed to implement unsized - // rvalues, triggers stackprobe even if %rax < 0x1000. - // Thus we have to check %r11 first to avoid segfault. - cmp $$0x1000,%r11 - jna 3f - 2: - sub $$0x1000,%rsp - test %rsp,8(%rsp) - sub $$0x1000,%r11 - cmp $$0x1000,%r11 - ja 2b - - 3: - // Finish up the last remaining stack space requested, getting the last - // bits out of r11 - sub %r11,%rsp - test %rsp,8(%rsp) - - // Restore the stack pointer to what it previously was when entering - // this function. The caller will readjust the stack pointer after we - // return. - add %rax,%rsp - - ret - " ::: "memory" : "volatile"); - ::core::intrinsics::unreachable(); -} - -#[naked] -#[no_mangle] -#[cfg(all(target_arch = "x86", not(feature = "mangled-names")))] -pub unsafe extern "C" fn __rust_probestack() { - // This is the same as x86_64 above, only translated for 32-bit sizes. Note - // that on Unix we're expected to restore everything as it was, this - // function basically can't tamper with anything. - // - // The ABI here is the same as x86_64, except everything is 32-bits large. - asm!(" - push %ecx - mov %eax,%ecx - - cmp $$0x1000,%ecx - jna 3f - 2: - sub $$0x1000,%esp - test %esp,8(%esp) - sub $$0x1000,%ecx - cmp $$0x1000,%ecx - ja 2b - - 3: - sub %ecx,%esp - test %esp,8(%esp) - - add %eax,%esp - pop %ecx - ret - " ::: "memory" : "volatile"); - ::core::intrinsics::unreachable(); -} +// The code here moved to probestack_*.S, to support debugger frame information. diff --git a/src/probestack_x86.S b/src/probestack_x86.S new file mode 100644 index 000000000..fbbaf7525 --- /dev/null +++ b/src/probestack_x86.S @@ -0,0 +1,38 @@ +// This is the same as x86_64, only translated for 32-bit sizes. Note that on +// Unix we're expected to restore everything as it was, this function basically +// can't tamper with anything. +// +// The ABI here is the same as x86_64, except everything is 32-bits large. + +.text +.globl __rust_probestack +.type __rust_probestack, @function +__rust_probestack: + .cfi_startproc + push %ebp + .cfi_def_cfa_offset 8 + .cfi_offset 6, -8 + mov %esp, %ebp + .cfi_def_cfa_register 6 + push %ecx + mov %eax,%ecx + + cmp $0x1000,%ecx + jna 3f +2: + sub $0x1000,%esp + test %esp,8(%esp) + sub $0x1000,%ecx + cmp $0x1000,%ecx + ja 2b + +3: + sub %ecx,%esp + test %esp,8(%esp) + + add %eax,%esp + pop %ecx + leave + .cfi_def_cfa 7, 8 + ret + .cfi_endproc diff --git a/src/probestack_x86_64.S b/src/probestack_x86_64.S new file mode 100644 index 000000000..50312c7a3 --- /dev/null +++ b/src/probestack_x86_64.S @@ -0,0 +1,57 @@ +// Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, +// ensuring that if any pages are unmapped we'll make a page fault. +// +// The ABI here is that the stack frame size is located in `%eax`. Upon +// return we're not supposed to modify `%esp` or `%eax`. + +.text +.p2align 4,,15 +.globl __rust_probestack +.type __rust_probestack, @function +__rust_probestack: + .cfi_startproc + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset 6, -16 + movq %rsp, %rbp + .cfi_def_cfa_register 6 + // duplicate %rax as we're clobbering %r11 + mov %rax,%r11 + + // Main loop, taken in one page increments. We're decrementing rsp by + // a page each time until there's less than a page remaining. We're + // guaranteed that this function isn't called unless there's more than a + // page needed. + // + // Note that we're also testing against `8(%rsp)` to account for the 8 + // bytes pushed on the stack orginally with our return address. Using + // `8(%rsp)` simulates us testing the stack pointer in the caller's + // context. + + // It's usually called when %rax >= 0x1000, but that's not always true. + // Dynamic stack allocation, which is needed to implement unsized + // rvalues, triggers stackprobe even if %rax < 0x1000. + // Thus we have to check %r11 first to avoid segfault. + cmp $0x1000,%r11 + jna 3f +2: + sub $0x1000,%rsp + test %rsp,8(%rsp) + sub $0x1000,%r11 + cmp $0x1000,%r11 + ja 2b + +3: + // Finish up the last remaining stack space requested, getting the last + // bits out of r11 + sub %r11,%rsp + test %rsp,8(%rsp) + + // Restore the stack pointer to what it previously was when entering + // this function. The caller will readjust the stack pointer after we + // return. + add %rax,%rsp + leave + .cfi_def_cfa 7, 8 + ret + .cfi_endproc