summaryrefslogtreecommitdiffstats
path: root/vendor/psm/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/psm/src')
-rw-r--r--vendor/psm/src/arch/aarch64_armasm.asm38
-rw-r--r--vendor/psm/src/arch/aarch_aapcs64.s85
-rw-r--r--vendor/psm/src/arch/arm_aapcs.s106
-rw-r--r--vendor/psm/src/arch/arm_armasm.asm39
-rw-r--r--vendor/psm/src/arch/mips64_eabi.s87
-rw-r--r--vendor/psm/src/arch/mips_eabi.s88
-rw-r--r--vendor/psm/src/arch/powerpc32.s76
-rw-r--r--vendor/psm/src/arch/powerpc64.s90
-rw-r--r--vendor/psm/src/arch/powerpc64_openpower.s86
-rw-r--r--vendor/psm/src/arch/psm.h10
-rw-r--r--vendor/psm/src/arch/riscv.s64
-rw-r--r--vendor/psm/src/arch/riscv64.s64
-rw-r--r--vendor/psm/src/arch/sparc64.s67
-rw-r--r--vendor/psm/src/arch/sparc_sysv.s65
-rw-r--r--vendor/psm/src/arch/wasm32.s60
-rw-r--r--vendor/psm/src/arch/x86.s91
-rw-r--r--vendor/psm/src/arch/x86_64.s87
-rw-r--r--vendor/psm/src/arch/x86_64_msvc.asm61
-rw-r--r--vendor/psm/src/arch/x86_64_windows_gnu.s95
-rw-r--r--vendor/psm/src/arch/x86_msvc.asm70
-rw-r--r--vendor/psm/src/arch/x86_windows_gnu.s94
-rw-r--r--vendor/psm/src/arch/zseries_linux.s75
-rw-r--r--vendor/psm/src/lib.rs406
23 files changed, 2004 insertions, 0 deletions
diff --git a/vendor/psm/src/arch/aarch64_armasm.asm b/vendor/psm/src/arch/aarch64_armasm.asm
new file mode 100644
index 000000000..95349f9cc
--- /dev/null
+++ b/vendor/psm/src/arch/aarch64_armasm.asm
@@ -0,0 +1,38 @@
+ AREA |.text|, CODE, READONLY
+
+ GLOBAL |rust_psm_stack_direction|
+ ALIGN 4
+|rust_psm_stack_direction| PROC
+ orr w0, wzr, #2
+ ret
+ ENDP
+
+
+ GLOBAL |rust_psm_stack_pointer|
+ ALIGN 4
+|rust_psm_stack_pointer| PROC
+ mov x0, sp
+ ret
+ ENDP
+
+
+ GLOBAL |rust_psm_replace_stack|
+ ALIGN 4
+|rust_psm_replace_stack| PROC
+ mov sp, x2
+ br x1
+ ENDP
+
+ GLOBAL |rust_psm_on_stack|
+ ALIGN 4
+|rust_psm_on_stack| PROC
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+ mov sp, x3
+ blr x2
+ mov sp, x29
+ ldp x29, x30, [sp], #16
+ ret
+ ENDP
+
+ END
diff --git a/vendor/psm/src/arch/aarch_aapcs64.s b/vendor/psm/src/arch/aarch_aapcs64.s
new file mode 100644
index 000000000..55917f329
--- /dev/null
+++ b/vendor/psm/src/arch/aarch_aapcs64.s
@@ -0,0 +1,85 @@
+#include "psm.h"
+
+.text
+
+#if CFG_TARGET_OS_darwin || CFG_TARGET_OS_macos || CFG_TARGET_OS_ios
+
+#define GLOBL(fnname) .globl _##fnname
+#define TYPE(fnname)
+#define FUNCTION(fnname) _##fnname
+#define SIZE(fnname,endlabel)
+
+#else
+
+#define GLOBL(fnname) .globl fnname
+#define TYPE(fnname) .type fnname,@function
+#define FUNCTION(fnname) fnname
+#define SIZE(fnname,endlabel) .size fnname,endlabel-fnname
+
+#endif
+
+
+GLOBL(rust_psm_stack_direction)
+.p2align 2
+TYPE(rust_psm_stack_direction)
+FUNCTION(rust_psm_stack_direction):
+/* extern "C" fn() -> u8 */
+.cfi_startproc
+ orr w0, wzr, #STACK_DIRECTION_DESCENDING
+ ret
+.rust_psm_stack_direction_end:
+SIZE(rust_psm_stack_direction,.rust_psm_stack_direction_end)
+.cfi_endproc
+
+
+GLOBL(rust_psm_stack_pointer)
+.p2align 2
+TYPE(rust_psm_stack_pointer)
+FUNCTION(rust_psm_stack_pointer):
+/* extern "C" fn() -> *mut u8 */
+.cfi_startproc
+ mov x0, sp
+ ret
+.rust_psm_stack_pointer_end:
+SIZE(rust_psm_stack_pointer,.rust_psm_stack_pointer_end)
+.cfi_endproc
+
+
+GLOBL(rust_psm_replace_stack)
+.p2align 2
+TYPE(rust_psm_replace_stack)
+FUNCTION(rust_psm_replace_stack):
+/* extern "C" fn(r0: usize, r1: extern "C" fn(usize), r2: *mut u8) */
+.cfi_startproc
+/* All we gotta do is set the stack pointer to %rdx & tail-call the callback in %rsi */
+ mov sp, x2
+ br x1
+.rust_psm_replace_stack_end:
+SIZE(rust_psm_replace_stack,.rust_psm_replace_stack_end)
+.cfi_endproc
+
+
+GLOBL(rust_psm_on_stack)
+.p2align 2
+TYPE(rust_psm_on_stack)
+FUNCTION(rust_psm_on_stack):
+/* extern "C" fn(r0: usize, r1: usize, r2: extern "C" fn(usize, usize), r3: *mut u8) */
+.cfi_startproc
+ stp x29, x30, [sp, #-16]!
+ .cfi_def_cfa sp, 16
+ mov x29, sp
+ .cfi_def_cfa x29, 16
+ .cfi_offset x29, -16
+ .cfi_offset x30, -8
+ mov sp, x3
+ blr x2
+ mov sp, x29
+ .cfi_def_cfa sp, 16
+ ldp x29, x30, [sp], #16
+ .cfi_def_cfa sp, 0
+ .cfi_restore x29
+ .cfi_restore x30
+ ret
+.rust_psm_on_stack_end:
+SIZE(rust_psm_on_stack,.rust_psm_on_stack_end)
+.cfi_endproc
diff --git a/vendor/psm/src/arch/arm_aapcs.s b/vendor/psm/src/arch/arm_aapcs.s
new file mode 100644
index 000000000..c2fa9d81d
--- /dev/null
+++ b/vendor/psm/src/arch/arm_aapcs.s
@@ -0,0 +1,106 @@
+#include "psm.h"
+
+.text
+.syntax unified
+
+#if CFG_TARGET_OS_darwin || CFG_TARGET_OS_macos || CFG_TARGET_OS_ios
+
+#define GLOBL(fnname) .globl _##fnname
+#define THUMBTYPE(fnname) .thumb_func _##fnname
+#define FUNCTION(fnname) _##fnname
+#define THUMBFN .code 16
+#define SIZE(fnname,endlabel)
+#define FNSTART
+#define CANTUNWIND
+#define FNEND
+
+#else
+
+#define GLOBL(fnname) .globl fnname
+#define THUMBTYPE(fnname) .type fnname,%function
+#define FUNCTION(fnname) fnname
+#define THUMBFN .code 16
+#define SIZE(fnname,endlabel) .size fnname,endlabel-fnname
+#define FNSTART .fnstart
+#define CANTUNWIND .cantunwind
+#define FNEND .fnend
+
+#endif
+
+
+GLOBL(rust_psm_stack_direction)
+.p2align 2
+THUMBTYPE(rust_psm_stack_direction)
+THUMBFN
+FUNCTION(rust_psm_stack_direction):
+/* extern "C" fn() -> u8 */
+FNSTART
+.cfi_startproc
+ /* movs to support Thumb-1 */
+ movs r0, #STACK_DIRECTION_DESCENDING
+ bx lr
+.rust_psm_stack_direction_end:
+SIZE(rust_psm_stack_direction,.rust_psm_stack_direction_end)
+.cfi_endproc
+CANTUNWIND
+FNEND
+
+GLOBL(rust_psm_stack_pointer)
+.p2align 2
+THUMBTYPE(rust_psm_stack_pointer)
+THUMBFN
+FUNCTION(rust_psm_stack_pointer):
+/* extern "C" fn() -> *mut u8 */
+FNSTART
+.cfi_startproc
+ mov r0, sp
+ bx lr
+.rust_psm_stack_pointer_end:
+SIZE(rust_psm_stack_pointer,.rust_psm_stack_pointer_end)
+.cfi_endproc
+CANTUNWIND
+FNEND
+
+
+GLOBL(rust_psm_replace_stack)
+.p2align 2
+THUMBTYPE(rust_psm_replace_stack)
+THUMBFN
+FUNCTION(rust_psm_replace_stack):
+/* extern "C" fn(r0: usize, r1: extern "C" fn(usize), r2: *mut u8) */
+FNSTART
+.cfi_startproc
+/* All we gotta do is set the stack pointer to %rdx & tail-call the callback in %rsi */
+ mov sp, r2
+ bx r1
+.rust_psm_replace_stack_end:
+SIZE(rust_psm_replace_stack,.rust_psm_replace_stack_end)
+.cfi_endproc
+CANTUNWIND
+FNEND
+
+
+GLOBL(rust_psm_on_stack)
+.p2align 2
+THUMBTYPE(rust_psm_on_stack)
+THUMBFN
+FUNCTION(rust_psm_on_stack):
+/* extern "C" fn(r0: usize, r1: usize, r2: extern "C" fn(usize, usize), r3: *mut u8) */
+FNSTART
+.cfi_startproc
+ push {r4, lr}
+ .cfi_def_cfa_offset 8
+ mov r4, sp
+ .cfi_def_cfa_register r4
+ .cfi_offset lr, -4
+ .cfi_offset r4, -8
+ mov sp, r3
+ blx r2
+ mov sp, r4
+ .cfi_restore sp
+ pop {r4, pc}
+.rust_psm_on_stack_end:
+SIZE(rust_psm_on_stack,.rust_psm_on_stack_end)
+.cfi_endproc
+CANTUNWIND
+FNEND
diff --git a/vendor/psm/src/arch/arm_armasm.asm b/vendor/psm/src/arch/arm_armasm.asm
new file mode 100644
index 000000000..ab8a5bcf0
--- /dev/null
+++ b/vendor/psm/src/arch/arm_armasm.asm
@@ -0,0 +1,39 @@
+ THUMB
+ AREA |.text|, CODE, READONLY
+
+
+ GLOBAL |rust_psm_stack_direction|
+ ALIGN 4
+|rust_psm_stack_direction| PROC
+ movs r0, #2
+ bx lr
+ ENDP
+
+ GLOBAL |rust_psm_stack_pointer|
+ ALIGN 4
+|rust_psm_stack_pointer| PROC
+ mov r0, sp
+ bx lr
+ ENDP
+
+
+ GLOBAL |rust_psm_replace_stack|
+ ALIGN 4
+|rust_psm_replace_stack| PROC
+ mov sp, r2
+ bx r1
+ ENDP
+
+
+ GLOBAL |rust_psm_on_stack|
+ ALIGN 4
+|rust_psm_on_stack| PROC
+ push {r4, lr}
+ mov r4, sp
+ mov sp, r3
+ blx r2
+ mov sp, r4
+ pop {r4, pc}
+ ENDP
+
+ END
diff --git a/vendor/psm/src/arch/mips64_eabi.s b/vendor/psm/src/arch/mips64_eabi.s
new file mode 100644
index 000000000..72bc01eb7
--- /dev/null
+++ b/vendor/psm/src/arch/mips64_eabi.s
@@ -0,0 +1,87 @@
+/*
+Not only MIPS has 20 different ABIs... nobody tells anybody what specific variant of which ABI is
+used where.
+
+This is an "EABI" implementation based on the following page:
+
+http://www.cygwin.com/ml/binutils/2003-06/msg00436.html
+*/
+
+#include "psm.h"
+
+.set noreorder /* we’ll manage the delay slots on our own, thanks! */
+
+.text
+.globl rust_psm_stack_direction
+.p2align 3
+.type rust_psm_stack_direction,@function
+.ent rust_psm_stack_direction
+/* extern "C" fn() -> u8 */
+rust_psm_stack_direction:
+.cfi_startproc
+ jr $31
+ addiu $2, $zero, STACK_DIRECTION_DESCENDING
+.end rust_psm_stack_direction
+.rust_psm_stack_direction_end:
+.size rust_psm_stack_direction,.rust_psm_stack_direction_end-rust_psm_stack_direction
+.cfi_endproc
+
+
+.globl rust_psm_stack_pointer
+.p2align 3
+.type rust_psm_stack_pointer,@function
+.ent rust_psm_stack_pointer
+/* extern "C" fn() -> *mut u8 */
+rust_psm_stack_pointer:
+.cfi_startproc
+ jr $31
+ move $2, $29
+.end rust_psm_stack_pointer
+.rust_psm_stack_pointer_end:
+.size rust_psm_stack_pointer,.rust_psm_stack_pointer_end-rust_psm_stack_pointer
+.cfi_endproc
+
+
+
+.globl rust_psm_replace_stack
+.p2align 3
+.type rust_psm_replace_stack,@function
+.ent rust_psm_replace_stack
+/* extern "C" fn(r4: usize, r5: extern "C" fn(usize), r6: *mut u8) */
+rust_psm_replace_stack:
+.cfi_startproc
+ move $25, $5
+ jr $5
+ move $29, $6
+.end rust_psm_replace_stack
+.rust_psm_replace_stack_end:
+.size rust_psm_replace_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
+
+
+.globl rust_psm_on_stack
+.p2align 3
+.type rust_psm_on_stack,@function
+.ent rust_psm_on_stack
+/* extern "C" fn(r4: usize, r5: usize, r6: extern "C" fn(usize), r7: *mut u8) */
+rust_psm_on_stack:
+.cfi_startproc
+ sd $29, -8($7)
+ sd $31, -16($7)
+ .cfi_def_cfa 7, 0
+ .cfi_offset 31, -16
+ .cfi_offset 29, -8
+ move $25, $6
+ jalr $31, $6
+ daddiu $29, $7, -16
+ .cfi_def_cfa 29, 16
+ ld $31, 0($29)
+ .cfi_restore 31
+ ld $29, 8($29)
+ .cfi_restore 29
+ jr $31
+ nop
+.end rust_psm_on_stack
+.rust_psm_on_stack_end:
+.size rust_psm_on_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
diff --git a/vendor/psm/src/arch/mips_eabi.s b/vendor/psm/src/arch/mips_eabi.s
new file mode 100644
index 000000000..e08ed278a
--- /dev/null
+++ b/vendor/psm/src/arch/mips_eabi.s
@@ -0,0 +1,88 @@
+/*
+Not only MIPS has 20 different ABIs... nobody tells anybody what specific variant of which ABI is
+used where.
+
+This is an "EABI" implementation based on the following page:
+
+http://www.cygwin.com/ml/binutils/2003-06/msg00436.html
+*/
+
+#include "psm.h"
+
+.set noreorder /* we’ll manage the delay slots on our own, thanks! */
+
+.text
+.abicalls
+.globl rust_psm_stack_direction
+.p2align 2
+.type rust_psm_stack_direction,@function
+.ent rust_psm_stack_direction
+/* extern "C" fn() -> u8 */
+rust_psm_stack_direction:
+.cfi_startproc
+ jr $31
+ addiu $2, $zero, STACK_DIRECTION_DESCENDING
+.end rust_psm_stack_direction
+.rust_psm_stack_direction_end:
+.size rust_psm_stack_direction,.rust_psm_stack_direction_end-rust_psm_stack_direction
+.cfi_endproc
+
+
+.globl rust_psm_stack_pointer
+.p2align 2
+.type rust_psm_stack_pointer,@function
+.ent rust_psm_stack_pointer
+/* extern "C" fn() -> *mut u8 */
+rust_psm_stack_pointer:
+.cfi_startproc
+ jr $31
+ move $2, $29
+.end rust_psm_stack_pointer
+.rust_psm_stack_pointer_end:
+.size rust_psm_stack_pointer,.rust_psm_stack_pointer_end-rust_psm_stack_pointer
+.cfi_endproc
+
+
+
+.globl rust_psm_replace_stack
+.p2align 2
+.type rust_psm_replace_stack,@function
+.ent rust_psm_replace_stack
+/* extern "C" fn(r4: usize, r5: extern "C" fn(usize), r6: *mut u8) */
+rust_psm_replace_stack:
+.cfi_startproc
+ move $25, $5
+ jr $5
+ move $29, $6
+.end rust_psm_replace_stack
+.rust_psm_replace_stack_end:
+.size rust_psm_replace_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
+
+
+.globl rust_psm_on_stack
+.p2align 2
+.type rust_psm_on_stack,@function
+.ent rust_psm_on_stack
+/* extern "C" fn(r4: usize, r5: usize, r6: extern "C" fn(usize), r7: *mut u8) */
+rust_psm_on_stack:
+.cfi_startproc
+ sw $29, -4($7)
+ sw $31, -8($7)
+ .cfi_def_cfa 7, 0
+ .cfi_offset 31, -8
+ .cfi_offset 29, -4
+ move $25, $6
+ jalr $31, $6
+ addiu $29, $7, -8
+ .cfi_def_cfa 29, 8
+ lw $31, 0($29)
+ .cfi_restore 31
+ lw $29, 4($29)
+ .cfi_restore 29
+ jr $31
+ nop
+.end rust_psm_on_stack
+.rust_psm_on_stack_end:
+.size rust_psm_on_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
diff --git a/vendor/psm/src/arch/powerpc32.s b/vendor/psm/src/arch/powerpc32.s
new file mode 100644
index 000000000..1f7a08619
--- /dev/null
+++ b/vendor/psm/src/arch/powerpc32.s
@@ -0,0 +1,76 @@
+#include "psm.h"
+/* FIXME: this probably does not cover all ABIs? Tested with sysv only, possibly works for AIX as
+ well?
+*/
+
+.text
+.globl rust_psm_stack_direction
+.p2align 2
+.type rust_psm_stack_direction,@function
+rust_psm_stack_direction:
+/* extern "C" fn() -> u8 */
+.cfi_startproc
+ li 3, STACK_DIRECTION_DESCENDING
+ blr
+.rust_psm_stack_direction_end:
+.size rust_psm_stack_direction,.rust_psm_stack_direction_end-rust_psm_stack_direction
+.cfi_endproc
+
+
+.globl rust_psm_stack_pointer
+.p2align 2
+.type rust_psm_stack_pointer,@function
+rust_psm_stack_pointer:
+/* extern "C" fn() -> *mut u8 */
+.cfi_startproc
+ mr 3, 1
+ blr
+.rust_psm_stack_pointer_end:
+.size rust_psm_stack_pointer,.rust_psm_stack_pointer_end-rust_psm_stack_pointer
+.cfi_endproc
+
+
+.globl rust_psm_replace_stack
+.p2align 2
+.type rust_psm_replace_stack,@function
+rust_psm_replace_stack:
+/* extern "C" fn(3: usize, 4: extern "C" fn(usize), 5: *mut u8) */
+.cfi_startproc
+/* NOTE: perhaps add a debug-assertion for stack alignment? */
+ addi 5, 5, -16
+ mr 1, 5
+ mtctr 4
+ bctr
+.rust_psm_replace_stack_end:
+.size rust_psm_replace_stack,.rust_psm_replace_stack_end-rust_psm_replace_stack
+.cfi_endproc
+
+
+.globl rust_psm_on_stack
+.p2align 2
+.type rust_psm_on_stack,@function
+rust_psm_on_stack:
+/* extern "C" fn(3: usize, 4: usize, 5: extern "C" fn(usize, usize), 6: *mut u8) */
+.cfi_startproc
+ mflr 0
+ stw 0, -24(6)
+ sub 6, 6, 1
+ addi 6, 6, -32
+ stwux 1, 1, 6
+ .cfi_def_cfa r1, 32
+ .cfi_offset r1, -32
+ .cfi_offset lr, -24
+ mtctr 5
+ bctrl
+ lwz 0, 8(1)
+ mtlr 0
+ .cfi_restore lr
+ /* FIXME: after this instruction backtrace breaks until control returns to the caller
+ That being said compiler-generated code has the same issue, so I guess that is fine for now?
+ */
+ lwz 1, 0(1)
+ .cfi_restore r1
+ blr
+.rust_psm_on_stack_end:
+.size rust_psm_on_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
diff --git a/vendor/psm/src/arch/powerpc64.s b/vendor/psm/src/arch/powerpc64.s
new file mode 100644
index 000000000..1504a8c01
--- /dev/null
+++ b/vendor/psm/src/arch/powerpc64.s
@@ -0,0 +1,90 @@
+/* Implementation of the AIX-like PowerPC ABI. Seems to be used by the big-endian PowerPC targets.
+ The following references were used during the implementation of this code:
+
+ https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/com.ibm.aix.alangref/idalangref_rntime_stack.htm
+ https://www.ibm.com/support/knowledgecenter/en/ssw_aix_72/com.ibm.aix.alangref/idalangref_reg_use_conv.htm
+ https://www.ibm.com/developerworks/library/l-powasm4/index.html
+*/
+
+#include "psm.h"
+
+.text
+.globl rust_psm_stack_direction
+.p2align 2
+.type rust_psm_stack_direction,@function
+rust_psm_stack_direction:
+/* extern "C" fn() -> u8 */
+.cfi_startproc
+ li 3, STACK_DIRECTION_DESCENDING
+ blr
+.rust_psm_stack_direction_end:
+.size rust_psm_stack_direction,.rust_psm_stack_direction_end-rust_psm_stack_direction
+.cfi_endproc
+
+
+.globl rust_psm_stack_pointer
+.p2align 2
+.type rust_psm_stack_pointer,@function
+rust_psm_stack_pointer:
+/* extern "C" fn() -> *mut u8 */
+.cfi_startproc
+ mr 3, 1
+ blr
+.rust_psm_stack_pointer_end:
+.size rust_psm_stack_pointer,.rust_psm_stack_pointer_end-rust_psm_stack_pointer
+.cfi_endproc
+
+
+.globl rust_psm_replace_stack
+.p2align 2
+.type rust_psm_replace_stack,@function
+rust_psm_replace_stack:
+/* extern "C" fn(3: usize, 4: extern "C" fn(usize), 5: *mut u8) */
+.cfi_startproc
+ ld 2, 8(4)
+ ld 4, 0(4)
+ /* do not allocate the whole 112-byte sized frame, we know wont be used */
+ addi 5, 5, -48
+ mr 1, 5
+ mtctr 4
+ bctr
+.rust_psm_replace_stack_end:
+.size rust_psm_replace_stack,.rust_psm_replace_stack_end-rust_psm_replace_stack
+.cfi_endproc
+
+
+.globl rust_psm_on_stack
+.p2align 2
+.type rust_psm_on_stack,@function
+rust_psm_on_stack:
+/* extern "C" fn(3: usize, 4: usize, 5: extern "C" fn(usize, usize), 6: *mut u8) */
+.cfi_startproc
+ mflr 0
+ std 2, -72(6)
+ std 0, -8(6)
+ sub 6, 6, 1
+ addi 6, 6, -112
+ stdux 1, 1, 6
+ .cfi_def_cfa r1, 112
+ .cfi_offset r1, -112
+ .cfi_offset r2, -72
+ .cfi_offset lr, -8
+ /* load the function pointer from TOC and make the call */
+ ld 2, 8(5)
+ ld 5, 0(5)
+ mtctr 5
+ bctrl
+ ld 2, 40(1)
+ .cfi_restore r2
+ ld 0, 104(1)
+ mtlr 0
+ .cfi_restore lr
+ /* FIXME: after this instruction backtrace breaks until control returns to the caller.
+ That being said compiler-generated code has the same issue, so I guess that is fine for now?
+ */
+ ld 1, 0(1)
+ .cfi_restore r1
+ blr
+.rust_psm_on_stack_end:
+.size rust_psm_on_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
diff --git a/vendor/psm/src/arch/powerpc64_openpower.s b/vendor/psm/src/arch/powerpc64_openpower.s
new file mode 100644
index 000000000..eb3c1c174
--- /dev/null
+++ b/vendor/psm/src/arch/powerpc64_openpower.s
@@ -0,0 +1,86 @@
+/* Implementation of stack swtiching routines for OpenPOWER 64-bit ELF ABI
+ The specification can be found at
+ http://openpowerfoundation.org/wp-content/uploads/resources/leabi/content/ch_preface.html
+
+ This ABI is usually used by the ppc64le targets.
+*/
+
+#include "psm.h"
+
+.text
+.abiversion 2
+
+
+.globl rust_psm_stack_direction
+.p2align 4
+.type rust_psm_stack_direction,@function
+rust_psm_stack_direction:
+/* extern "C" fn() -> u8 */
+.cfi_startproc
+ li 3, STACK_DIRECTION_DESCENDING
+ blr
+.rust_psm_stack_direction_end:
+.size rust_psm_stack_direction,.rust_psm_stack_direction_end-rust_psm_stack_direction
+.cfi_endproc
+
+
+.globl rust_psm_stack_pointer
+.p2align 4
+.type rust_psm_stack_pointer,@function
+rust_psm_stack_pointer:
+/* extern "C" fn() -> *mut u8 */
+.cfi_startproc
+ mr 3, 1
+ blr
+.rust_psm_stack_pointer_end:
+.size rust_psm_stack_pointer,.rust_psm_stack_pointer_end-rust_psm_stack_pointer
+.cfi_endproc
+
+
+.globl rust_psm_replace_stack
+.p2align 4
+.type rust_psm_replace_stack,@function
+rust_psm_replace_stack:
+/* extern "C" fn(3: usize, 4: extern "C" fn(usize), 5: *mut u8) */
+.cfi_startproc
+ addi 5, 5, -32
+ mtctr 4
+ mr 12, 4
+ mr 1, 5
+ bctr
+.rust_psm_replace_stack_end:
+.size rust_psm_replace_stack,.rust_psm_replace_stack_end-rust_psm_replace_stack
+.cfi_endproc
+
+
+
+.globl rust_psm_on_stack
+.p2align 4
+.type rust_psm_on_stack,@function
+rust_psm_on_stack:
+/* extern "C" fn(3: usize, 4: usize, 5: extern "C" fn(usize, usize), 6: *mut u8) */
+.cfi_startproc
+ mflr 0
+ std 0, -8(6)
+ std 2, -24(6)
+ sub 6, 6, 1
+ addi 6, 6, -48
+ stdux 1, 1, 6
+ .cfi_def_cfa r1, 48
+ .cfi_offset r1, -48
+ .cfi_offset r2, -24
+ .cfi_offset lr, -8
+ mr 12, 5
+ mtctr 5
+ bctrl
+ ld 2, 24(1)
+ .cfi_restore r2
+ ld 0, 40(1)
+ mtlr 0
+ .cfi_restore lr
+ /* FIXME: after this instructin backtrace breaks until control returns to the caller */
+ ld 1, 0(1)
+ blr
+.rust_psm_on_stack_end:
+.size rust_psm_on_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
diff --git a/vendor/psm/src/arch/psm.h b/vendor/psm/src/arch/psm.h
new file mode 100644
index 000000000..c1137f984
--- /dev/null
+++ b/vendor/psm/src/arch/psm.h
@@ -0,0 +1,10 @@
+#define STACK_DIRECTION_ASCENDING 1
+#define STACK_DIRECTION_DESCENDING 2
+
+
+/*
+Various defines for values produced by `-DCFG_TARGET_*` flags. Only needs to be mutually unique
+*/
+#define darwin 1
+#define macos 2
+#define ios 3
diff --git a/vendor/psm/src/arch/riscv.s b/vendor/psm/src/arch/riscv.s
new file mode 100644
index 000000000..4972993c9
--- /dev/null
+++ b/vendor/psm/src/arch/riscv.s
@@ -0,0 +1,64 @@
+#include "psm.h"
+
+.text
+.globl rust_psm_stack_direction
+.p2align 2
+.type rust_psm_stack_direction,@function
+rust_psm_stack_direction:
+/* extern "C" fn() -> u8 */
+.cfi_startproc
+ li x10, STACK_DIRECTION_DESCENDING
+ jr x1
+.rust_psm_stack_direction_end:
+.size rust_psm_stack_direction,.rust_psm_stack_direction_end-rust_psm_stack_direction
+.cfi_endproc
+
+
+.globl rust_psm_stack_pointer
+.p2align 2
+.type rust_psm_stack_pointer,@function
+rust_psm_stack_pointer:
+/* extern "C" fn() -> *mut u8 */
+.cfi_startproc
+ add x10, x2, x0
+ jr x1
+.rust_psm_stack_pointer_end:
+.size rust_psm_stack_pointer,.rust_psm_stack_pointer_end-rust_psm_stack_pointer
+.cfi_endproc
+
+
+.globl rust_psm_replace_stack
+.p2align 2
+.type rust_psm_replace_stack,@function
+rust_psm_replace_stack:
+/* extern "C" fn(x10: usize, x11: extern "C" fn(usize), x12: *mut u8) */
+.cfi_startproc
+ add x2, x12, x0
+ jr x11
+.rust_psm_replace_stack_end:
+.size rust_psm_replace_stack,.rust_psm_replace_stack_end-rust_psm_replace_stack
+.cfi_endproc
+
+
+.globl rust_psm_on_stack
+.p2align 2
+.type rust_psm_on_stack,@function
+rust_psm_on_stack:
+/* extern "C" fn(x10: usize, x11: usize, x12: extern "C" fn(usize, usize), x13: *mut u8) */
+.cfi_startproc
+ sw x1, -12(x13)
+ sw x2, -16(x13)
+ .cfi_def_cfa x13, 0
+ .cfi_offset x1, -12
+ .cfi_offset x2, -16
+ addi x2, x13, -16
+ .cfi_def_cfa x2, -16
+ jalr x1, x12, 0
+ lw x1, 4(x2)
+ .cfi_restore x1
+ lw x2, 0(x2)
+ .cfi_restore x2
+ jr x1
+.rust_psm_on_stack_end:
+.size rust_psm_on_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
diff --git a/vendor/psm/src/arch/riscv64.s b/vendor/psm/src/arch/riscv64.s
new file mode 100644
index 000000000..1b275ec27
--- /dev/null
+++ b/vendor/psm/src/arch/riscv64.s
@@ -0,0 +1,64 @@
+#include "psm.h"
+
+.text
+.globl rust_psm_stack_direction
+.p2align 2
+.type rust_psm_stack_direction,@function
+rust_psm_stack_direction:
+/* extern "C" fn() -> u8 */
+.cfi_startproc
+ li x10, STACK_DIRECTION_DESCENDING
+ jr x1
+.rust_psm_stack_direction_end:
+.size rust_psm_stack_direction,.rust_psm_stack_direction_end-rust_psm_stack_direction
+.cfi_endproc
+
+
+.globl rust_psm_stack_pointer
+.p2align 2
+.type rust_psm_stack_pointer,@function
+rust_psm_stack_pointer:
+/* extern "C" fn() -> *mut u8 */
+.cfi_startproc
+ add x10, x2, x0
+ jr x1
+.rust_psm_stack_pointer_end:
+.size rust_psm_stack_pointer,.rust_psm_stack_pointer_end-rust_psm_stack_pointer
+.cfi_endproc
+
+
+.globl rust_psm_replace_stack
+.p2align 2
+.type rust_psm_replace_stack,@function
+rust_psm_replace_stack:
+/* extern "C" fn(x10: usize, x11: extern "C" fn(usize), x12: *mut u8) */
+.cfi_startproc
+ add x2, x12, x0
+ jr x11
+.rust_psm_replace_stack_end:
+.size rust_psm_replace_stack,.rust_psm_replace_stack_end-rust_psm_replace_stack
+.cfi_endproc
+
+
+.globl rust_psm_on_stack
+.p2align 2
+.type rust_psm_on_stack,@function
+rust_psm_on_stack:
+/* extern "C" fn(x10: usize, x11: usize, x12: extern "C" fn(usize, usize), x13: *mut u8) */
+.cfi_startproc
+ sd x1, -8(x13)
+ sd x2, -16(x13)
+ .cfi_def_cfa x13, 0
+ .cfi_offset x1, -8
+ .cfi_offset x2, -16
+ addi x2, x13, -16
+ .cfi_def_cfa x2, -16
+ jalr x1, x12, 0
+ ld x1, 8(x2)
+ .cfi_restore x1
+ ld x2, 0(x2)
+ .cfi_restore x2
+ jr x1
+.rust_psm_on_stack_end:
+.size rust_psm_on_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
diff --git a/vendor/psm/src/arch/sparc64.s b/vendor/psm/src/arch/sparc64.s
new file mode 100644
index 000000000..a0db27dde
--- /dev/null
+++ b/vendor/psm/src/arch/sparc64.s
@@ -0,0 +1,67 @@
+#include "psm.h"
+
+.text
+.globl rust_psm_stack_direction
+.p2align 2
+.type rust_psm_stack_direction,@function
+rust_psm_stack_direction:
+/* extern "C" fn() -> u8 */
+.cfi_startproc
+ jmpl %o7 + 8, %g0
+ mov STACK_DIRECTION_DESCENDING, %o0
+.rust_psm_stack_direction_end:
+.size rust_psm_stack_direction,.rust_psm_stack_direction_end-rust_psm_stack_direction
+.cfi_endproc
+
+
+.globl rust_psm_stack_pointer
+.p2align 2
+.type rust_psm_stack_pointer,@function
+rust_psm_stack_pointer:
+/* extern "C" fn() -> *mut u8 */
+.cfi_startproc
+ jmpl %o7 + 8, %g0
+ mov %o6, %o0
+.rust_psm_stack_pointer_end:
+.size rust_psm_stack_pointer,.rust_psm_stack_pointer_end-rust_psm_stack_pointer
+.cfi_endproc
+
+
+.globl rust_psm_replace_stack
+.p2align 2
+.type rust_psm_replace_stack,@function
+rust_psm_replace_stack:
+/* extern "C" fn(%i0: usize, %i1: extern "C" fn(usize), %i2: *mut u8) */
+.cfi_startproc
+ .cfi_def_cfa 0, 0
+ .cfi_return_column 0
+ jmpl %o1, %g0
+ /* WEIRD: Why is the LSB set for the %sp and %fp on SPARC?? */
+ add %o2, -0x7ff, %o6
+.rust_psm_replace_stack_end:
+.size rust_psm_replace_stack,.rust_psm_replace_stack_end-rust_psm_replace_stack
+.cfi_endproc
+
+
+.globl rust_psm_on_stack
+.p2align 2
+.type rust_psm_on_stack,@function
+rust_psm_on_stack:
+/* extern "C" fn(%i0: usize, %i1: usize, %i2: extern "C" fn(usize, usize), %i3: *mut u8) */
+.cfi_startproc
+ /* The fact that locals and saved register windows are offset by 2kB is
+ very nasty property of SPARC architecture and ABI. In this case it forces us to slice off
+ 2kB of the stack space outright for no good reason other than adapting to a botched design.
+ */
+ save %o3, -0x87f, %o6
+ .cfi_def_cfa_register %fp
+ .cfi_window_save
+ .cfi_register %r15, %r31
+ mov %i1, %o1
+ jmpl %i2, %o7
+ mov %i0, %o0
+ ret
+ restore
+.rust_psm_on_stack_end:
+.size rust_psm_on_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
diff --git a/vendor/psm/src/arch/sparc_sysv.s b/vendor/psm/src/arch/sparc_sysv.s
new file mode 100644
index 000000000..27d95e933
--- /dev/null
+++ b/vendor/psm/src/arch/sparc_sysv.s
@@ -0,0 +1,65 @@
+#include "psm.h"
+
+/* FIXME: this ABI has definitely not been verified at all */
+
+.text
+.globl rust_psm_stack_direction
+.p2align 2
+.type rust_psm_stack_direction,@function
+rust_psm_stack_direction:
+/* extern "C" fn() -> u8 */
+.cfi_startproc
+ jmpl %o7 + 8, %g0
+ mov STACK_DIRECTION_DESCENDING, %o0
+.rust_psm_stack_direction_end:
+.size rust_psm_stack_direction,.rust_psm_stack_direction_end-rust_psm_stack_direction
+.cfi_endproc
+
+
+.globl rust_psm_stack_pointer
+.p2align 2
+.type rust_psm_stack_pointer,@function
+rust_psm_stack_pointer:
+/* extern "C" fn() -> *mut u8 */
+.cfi_startproc
+ jmpl %o7 + 8, %g0
+ mov %o6, %o0
+.rust_psm_stack_pointer_end:
+.size rust_psm_stack_pointer,.rust_psm_stack_pointer_end-rust_psm_stack_pointer
+.cfi_endproc
+
+
+.globl rust_psm_replace_stack
+.p2align 2
+.type rust_psm_replace_stack,@function
+rust_psm_replace_stack:
+/* extern "C" fn(%i0: usize, %i1: extern "C" fn(usize), %i2: *mut u8) */
+.cfi_startproc
+ .cfi_def_cfa 0, 0
+ .cfi_return_column 0
+ jmpl %o1, %g0
+ /* WEIRD: Why is the LSB set for the %sp and %fp on SPARC?? */
+ add %o2, -0x3ff, %o6
+.rust_psm_replace_stack_end:
+.size rust_psm_replace_stack,.rust_psm_replace_stack_end-rust_psm_replace_stack
+.cfi_endproc
+
+
+.globl rust_psm_on_stack
+.p2align 2
+.type rust_psm_on_stack,@function
+rust_psm_on_stack:
+/* extern "C" fn(%i0: usize, %i1: usize, %i2: extern "C" fn(usize, usize), %i3: *mut u8) */
+.cfi_startproc
+ save %o3, -0x43f, %o6
+ .cfi_def_cfa_register %fp
+ .cfi_window_save
+ .cfi_register %r15, %r31
+ mov %i1, %o1
+ jmpl %i2, %o7
+ mov %i0, %o0
+ ret
+ restore
+.rust_psm_on_stack_end:
+.size rust_psm_on_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
diff --git a/vendor/psm/src/arch/wasm32.s b/vendor/psm/src/arch/wasm32.s
new file mode 100644
index 000000000..e3364e7af
--- /dev/null
+++ b/vendor/psm/src/arch/wasm32.s
@@ -0,0 +1,60 @@
+#include "psm.h"
+
+# Note that this function is not compiled when this package is uploaded to
+# crates.io, this source is only here as a reference for how the corresponding
+# wasm32.o was generated. This file can be compiled with:
+#
+# cpp psm/src/arch/wasm32.s | llvm-mc -o psm/src/arch/wasm32.o --arch=wasm32 -filetype=obj
+#
+# where you'll want to ensure that `llvm-mc` is from a relatively recent
+# version of LLVM.
+
+.globaltype __stack_pointer, i32
+
+.globl rust_psm_stack_direction
+.type rust_psm_stack_direction,@function
+rust_psm_stack_direction:
+.functype rust_psm_stack_direction () -> (i32)
+ i32.const STACK_DIRECTION_DESCENDING
+ end_function
+
+.globl rust_psm_stack_pointer
+.type rust_psm_stack_pointer,@function
+rust_psm_stack_pointer:
+.functype rust_psm_stack_pointer () -> (i32)
+ global.get __stack_pointer
+ end_function
+
+.globl rust_psm_on_stack
+.type rust_psm_on_stack,@function
+rust_psm_on_stack:
+.functype rust_psm_on_stack (i32, i32, i32, i32) -> ()
+ # get our new stack argument, then save the old stack
+ # pointer into that local
+ local.get 3
+ global.get __stack_pointer
+ local.set 3
+ global.set __stack_pointer
+
+ # Call our indirect function specified
+ local.get 0
+ local.get 1
+ local.get 2
+ call_indirect (i32, i32) -> ()
+
+ # restore the stack pointer before returning
+ local.get 3
+ global.set __stack_pointer
+ end_function
+
+.globl rust_psm_replace_stack
+.type rust_psm_replace_stack,@function
+rust_psm_replace_stack:
+.functype rust_psm_replace_stack (i32, i32, i32) -> ()
+ local.get 2
+ global.set __stack_pointer
+ local.get 0
+ local.get 1
+ call_indirect (i32) -> ()
+ unreachable
+ end_function
diff --git a/vendor/psm/src/arch/x86.s b/vendor/psm/src/arch/x86.s
new file mode 100644
index 000000000..2e388760d
--- /dev/null
+++ b/vendor/psm/src/arch/x86.s
@@ -0,0 +1,91 @@
+#include "psm.h"
+/* NOTE: fastcall calling convention used on all x86 targets */
+
+.text
+
+#if CFG_TARGET_OS_darwin || CFG_TARGET_OS_macos || CFG_TARGET_OS_ios
+
+#define GLOBL(fnname) .globl _##fnname
+#define TYPE(fnname)
+#define FUNCTION(fnname) _##fnname
+#define SIZE(fnname,endlabel)
+
+#else
+
+#define GLOBL(fnname) .globl fnname
+#define TYPE(fnname) .type fnname,@function
+#define FUNCTION(fnname) fnname
+#define SIZE(fnname,endlabel) .size fnname,endlabel-fnname
+
+#endif
+
+
+GLOBL(rust_psm_stack_direction)
+.p2align 4
+TYPE(rust_psm_stack_direction)
+FUNCTION(rust_psm_stack_direction):
+/* extern "fastcall" fn() -> u8 (%al) */
+.cfi_startproc
+ movb $STACK_DIRECTION_DESCENDING, %al # always descending on x86_64
+ retl
+.rust_psm_stack_direction_end:
+SIZE(rust_psm_stack_direction,.rust_psm_stack_direction_end)
+.cfi_endproc
+
+
+GLOBL(rust_psm_stack_pointer)
+.p2align 4
+TYPE(rust_psm_stack_pointer)
+FUNCTION(rust_psm_stack_pointer):
+/* extern "fastcall" fn() -> *mut u8 (%rax) */
+.cfi_startproc
+ leal 4(%esp), %eax
+ retl
+.rust_psm_stack_pointer_end:
+SIZE(rust_psm_stack_pointer,.rust_psm_stack_pointer_end)
+.cfi_endproc
+
+
+GLOBL(rust_psm_replace_stack)
+.p2align 4
+TYPE(rust_psm_replace_stack)
+FUNCTION(rust_psm_replace_stack):
+/* extern "fastcall" fn(%ecx: usize, %edx: extern "fastcall" fn(usize), 4(%esp): *mut u8) */
+.cfi_startproc
+/*
+ All we gotta do is set the stack pointer to 4(%esp) & tail-call the callback in %edx
+
+ Note, that the callee expects the stack to be offset by 4 bytes (normally, a return address
+ would be store there) off the required stack alignment on entry. To offset the stack in such a
+ way we use the `calll` instruction, however it would also be possible to to use plain `jmpl` but
+ would require to adjust the stack manually, which cannot be easily done, because the stack
+ pointer argument is already stored in memory.
+ */
+ movl 4(%esp), %esp
+ calll *%edx
+ ud2
+.rust_psm_replace_stack_end:
+SIZE(rust_psm_replace_stack,.rust_psm_replace_stack_end)
+.cfi_endproc
+
+
+GLOBL(rust_psm_on_stack)
+.p2align 4
+TYPE(rust_psm_on_stack)
+FUNCTION(rust_psm_on_stack):
+/* extern "fastcall" fn(%ecx: usize, %edx: usize, 4(%esp): extern "fastcall" fn(usize, usize), 8(%esp): *mut u8) */
+.cfi_startproc
+ pushl %ebp
+ .cfi_def_cfa %esp, 8
+ .cfi_offset %ebp, -8
+ movl %esp, %ebp
+ .cfi_def_cfa_register %ebp
+ movl 12(%ebp), %esp
+ calll *8(%ebp)
+ movl %ebp, %esp
+ popl %ebp
+ .cfi_def_cfa %esp, 4
+ retl $8
+.rust_psm_on_stack_end:
+SIZE(rust_psm_on_stack,.rust_psm_on_stack_end)
+.cfi_endproc
diff --git a/vendor/psm/src/arch/x86_64.s b/vendor/psm/src/arch/x86_64.s
new file mode 100644
index 000000000..5f5ece5b1
--- /dev/null
+++ b/vendor/psm/src/arch/x86_64.s
@@ -0,0 +1,87 @@
+#include "psm.h"
+/* NOTE: sysv64 calling convention is used on all x86_64 targets, including Windows! */
+
+.text
+
+#if CFG_TARGET_OS_darwin || CFG_TARGET_OS_macos || CFG_TARGET_OS_ios
+
+#define GLOBL(fnname) .globl _##fnname
+#define TYPE(fnname)
+#define FUNCTION(fnname) _##fnname
+#define SIZE(fnname,endlabel)
+
+#else
+
+#define GLOBL(fnname) .globl fnname
+#define TYPE(fnname) .type fnname,@function
+#define FUNCTION(fnname) fnname
+#define SIZE(fnname,endlabel) .size fnname,endlabel-fnname
+
+#endif
+
+
+GLOBL(rust_psm_stack_direction)
+.p2align 4
+TYPE(rust_psm_stack_direction)
+FUNCTION(rust_psm_stack_direction):
+/* extern "sysv64" fn() -> u8 (%al) */
+.cfi_startproc
+ movb $STACK_DIRECTION_DESCENDING, %al # always descending on x86_64
+ retq
+.rust_psm_stack_direction_end:
+SIZE(rust_psm_stack_direction,.rust_psm_stack_direction_end)
+.cfi_endproc
+
+
+GLOBL(rust_psm_stack_pointer)
+.p2align 4
+TYPE(rust_psm_stack_pointer)
+FUNCTION(rust_psm_stack_pointer):
+/* extern "sysv64" fn() -> *mut u8 (%rax) */
+.cfi_startproc
+ leaq 8(%rsp), %rax
+ retq
+.rust_psm_stack_pointer_end:
+SIZE(rust_psm_stack_pointer,.rust_psm_stack_pointer_end)
+.cfi_endproc
+
+
+GLOBL(rust_psm_replace_stack)
+.p2align 4
+TYPE(rust_psm_replace_stack)
+FUNCTION(rust_psm_replace_stack):
+/* extern "sysv64" fn(%rdi: usize, %rsi: extern "sysv64" fn(usize), %rdx: *mut u8) */
+.cfi_startproc
+/*
+ All we gotta do is set the stack pointer to %rdx & tail-call the callback in %rsi.
+
+ 8-byte offset necessary to account for the "return" pointer that would otherwise be placed onto
+ stack with a regular call
+*/
+ leaq -8(%rdx), %rsp
+ jmpq *%rsi
+.rust_psm_replace_stack_end:
+SIZE(rust_psm_replace_stack,.rust_psm_replace_stack_end)
+.cfi_endproc
+
+
+GLOBL(rust_psm_on_stack)
+.p2align 4
+TYPE(rust_psm_on_stack)
+FUNCTION(rust_psm_on_stack):
+/* extern "sysv64" fn(%rdi: usize, %rsi: usize, %rdx: extern "sysv64" fn(usize, usize), %rcx: *mut u8) */
+.cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa %rsp, 16
+ .cfi_offset %rbp, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+ movq %rcx, %rsp
+ callq *%rdx
+ movq %rbp, %rsp
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.rust_psm_on_stack_end:
+SIZE(rust_psm_on_stack,.rust_psm_on_stack_end)
+.cfi_endproc
diff --git a/vendor/psm/src/arch/x86_64_msvc.asm b/vendor/psm/src/arch/x86_64_msvc.asm
new file mode 100644
index 000000000..67d72832f
--- /dev/null
+++ b/vendor/psm/src/arch/x86_64_msvc.asm
@@ -0,0 +1,61 @@
+PUBLIC rust_psm_stack_direction
+PUBLIC rust_psm_stack_pointer
+PUBLIC rust_psm_replace_stack
+PUBLIC rust_psm_on_stack
+
+_TEXT SEGMENT
+
+; extern "sysv64" fn() -> u8 (%al)
+rust_psm_stack_direction PROC
+ mov al, 2
+ ret
+rust_psm_stack_direction ENDP
+
+; extern "sysv64" fn() -> *mut u8 (%rax)
+rust_psm_stack_pointer PROC
+ lea rax, [rsp + 8]
+ ret
+rust_psm_stack_pointer ENDP
+
+; extern "sysv64" fn(%rdi: usize, %rsi: extern "sysv64" fn(usize), %rdx: *mut u8, %rcx: *mut u8)
+rust_psm_replace_stack PROC
+ mov gs:[08h], rdx
+ mov gs:[10h], rcx
+ lea rsp, [rdx - 8]
+ jmp rsi
+rust_psm_replace_stack ENDP
+
+; extern "sysv64" fn(%rdi: usize, %rsi: usize,
+; %rdx: extern "sysv64" fn(usize, usize), %rcx: *mut u8, %r8: *mut u8)
+;
+; NB: on Windows for SEH to work at all, the pointers in TIB, thread information block, need to be
+; fixed up. Otherwise, it seems that exception mechanism on Windows will not bother looking for
+; exception handlers at *all* if they happen to fall outside the are specified in TIB.
+;
+; This necessitates an API difference from the usual 4-argument signature used elsewhere.
+;
+; FIXME: this needs a catch-all exception handler that aborts in case somebody unwinds into here.
+rust_psm_on_stack PROC FRAME
+ push rbp
+ .pushreg rbp
+ mov rbp, rsp
+ .setframe rbp, 0
+ .endprolog
+
+ push gs:[08h]
+ mov gs:[08h], rcx
+ push gs:[10h]
+ mov gs:[10h], r8
+ mov rsp, rcx
+ call rdx
+ lea rsp, [rbp - 010h]
+ pop gs:[10h]
+ pop gs:[08h]
+
+ pop rbp
+ ret
+rust_psm_on_stack ENDP
+
+_TEXT ENDS
+
+END
diff --git a/vendor/psm/src/arch/x86_64_windows_gnu.s b/vendor/psm/src/arch/x86_64_windows_gnu.s
new file mode 100644
index 000000000..8f1258356
--- /dev/null
+++ b/vendor/psm/src/arch/x86_64_windows_gnu.s
@@ -0,0 +1,95 @@
+.text
+
+.def rust_psm_stack_direction
+.scl 2
+.type 32
+.endef
+.globl rust_psm_stack_direction
+.p2align 4
+rust_psm_stack_direction:
+/* extern "sysv64" fn() -> u8 (%al) */
+.cfi_startproc
+ movb $2, %al # always descending on x86_64
+ retq
+.cfi_endproc
+
+.def rust_psm_stack_pointer
+.scl 2
+.type 32
+.endef
+.globl rust_psm_stack_pointer
+.p2align 4
+rust_psm_stack_pointer:
+/* extern "sysv64" fn() -> *mut u8 (%rax) */
+.cfi_startproc
+ leaq 8(%rsp), %rax
+ retq
+.cfi_endproc
+
+
+.def rust_psm_replace_stack
+.scl 2
+.type 32
+.endef
+.globl rust_psm_replace_stack
+.p2align 4
+rust_psm_replace_stack:
+/* extern "sysv64" fn(%rdi: usize, %rsi: extern "sysv64" fn(usize), %rdx: *mut u8, %rcx: *mut u8) */
+.cfi_startproc
+/*
+ All we gotta do is set the stack pointer to %rdx & tail-call the callback in %rsi.
+
+ 8-byte offset necessary to account for the "return" pointer that would otherwise be placed onto
+ stack with a regular call
+*/
+ movq %gs:0x08, %rdx
+ movq %gs:0x10, %rcx
+ leaq -8(%rdx), %rsp
+ jmpq *%rsi
+.cfi_endproc
+
+
+.def rust_psm_on_stack
+.scl 2
+.type 32
+.endef
+.globl rust_psm_on_stack
+.p2align 4
+rust_psm_on_stack:
+/*
+extern "sysv64" fn(%rdi: usize, %rsi: usize,
+ %rdx: extern "sysv64" fn(usize, usize), %rcx: *mut u8, %r8: *mut u8)
+
+NB: on Windows for SEH to work at all, the pointers in TIB, thread information block, need to be
+fixed up. Otherwise, it seems that exception mechanism on Windows will not bother looking for
+exception handlers at *all* if they happen to fall outside the are specified in TIB.
+
+This necessitates an API difference from the usual 4-argument signature used elsewhere.
+
+FIXME: this needs a catch-all exception handler that aborts in case somebody unwinds into here.
+*/
+.cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa %rsp, 16
+ .cfi_offset %rbp, -16
+ pushq %gs:0x08
+ .cfi_def_cfa %rsp, 24
+ pushq %gs:0x10
+ .cfi_def_cfa %rsp, 32
+
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+ movq %rcx, %gs:0x08
+ movq %r8, %gs:0x10
+ movq %rcx, %rsp
+ callq *%rdx
+ movq %rbp, %rsp
+
+ popq %gs:0x10
+ .cfi_def_cfa %rsp, 24
+ popq %gs:0x08
+ .cfi_def_cfa %rsp, 16
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.cfi_endproc
diff --git a/vendor/psm/src/arch/x86_msvc.asm b/vendor/psm/src/arch/x86_msvc.asm
new file mode 100644
index 000000000..3838759f7
--- /dev/null
+++ b/vendor/psm/src/arch/x86_msvc.asm
@@ -0,0 +1,70 @@
+; FIXME: this is weird, this works locally but not on appveyor?!??!
+
+.386
+.model flat
+
+ASSUME FS:NOTHING
+
+; WTF: PUBLIC conflicts with "SYSCALL" but "SYSCALL" is the only way to stop MASM from manging the
+; symbol names?
+;
+; PUBLIC @rust_psm_stack_direction@0
+; PUBLIC @rust_psm_stack_pointer@0
+; PUBLIC @rust_psm_replace_stack@12
+; PUBLIC @rust_psm_on_stack@16
+
+_TEXT SEGMENT
+
+; extern "fastcall" fn() -> u8 (%al)
+@rust_psm_stack_direction@0 PROC SYSCALL
+ mov al, 2
+ ret
+@rust_psm_stack_direction@0 ENDP
+
+; extern "fastcall" fn() -> *mut u8 (%rax)
+@rust_psm_stack_pointer@0 PROC SYSCALL
+ lea eax, [esp + 4]
+ ret
+@rust_psm_stack_pointer@0 ENDP
+
+; extern "fastcall" fn(%ecx: usize, %edx: extern "fastcall" fn(usize),
+; 4(%esp): *mut u8, 8(%esp): *mut u8)
+@rust_psm_replace_stack@16 PROC SYSCALL
+ mov eax, dword ptr [esp + 8]
+ mov fs:[08h], eax
+ mov esp, dword ptr [esp + 4]
+ mov fs:[04h], esp
+ jmp edx
+@rust_psm_replace_stack@16 ENDP
+
+; extern "fastcall" fn(%ecx: usize, %edx: usize, 4(%esp): extern "fastcall" fn(usize, usize),
+; 8(%esp): *mut u8, 12(%esp): *mut u8)
+;
+; NB: on Windows for SEH to work at all, the pointers in TIB, thread information block, need to be
+; fixed up. Otherwise, it seems that exception mechanism on Windows will not bother looking for
+; exception handlers at *all* if they happen to fall outside the are specified in TIB.
+;
+; This necessitates an API difference from the usual 4-argument signature used elsewhere.
+@rust_psm_on_stack@20 PROC SYSCALL
+ push ebp
+ mov ebp, esp
+
+ push fs:[0E0Ch]
+ push fs:[08h]
+ mov eax, dword ptr [ebp + 4 + 12]
+ mov dword ptr fs:[08h], eax
+ mov dword ptr fs:[0E0Ch], eax
+ push fs:[04h]
+ mov esp, dword ptr [ebp + 4 + 8]
+ mov dword ptr fs:[04h], esp
+ call dword ptr [ebp + 4 + 4]
+
+ lea esp, [ebp - 12]
+ pop fs:[04h]
+ pop fs:[08h]
+ pop fs:[0E0Ch]
+ pop ebp
+ ret 12
+@rust_psm_on_stack@20 ENDP
+
+END
diff --git a/vendor/psm/src/arch/x86_windows_gnu.s b/vendor/psm/src/arch/x86_windows_gnu.s
new file mode 100644
index 000000000..474d4168a
--- /dev/null
+++ b/vendor/psm/src/arch/x86_windows_gnu.s
@@ -0,0 +1,94 @@
+/* FIXME: this works locally but not on appveyor??!? */
+/* NOTE: fastcall calling convention used on all x86 targets */
+.text
+
+.def @rust_psm_stack_direction@0
+.scl 2
+.type 32
+.endef
+.globl @rust_psm_stack_direction@0
+.p2align 4
+@rust_psm_stack_direction@0:
+/* extern "fastcall" fn() -> u8 (%al) */
+.cfi_startproc
+ movb $2, %al # always descending on x86_64
+ retl
+.cfi_endproc
+
+
+.def @rust_psm_stack_pointer@0
+.scl 2
+.type 32
+.endef
+.globl @rust_psm_stack_pointer@0
+.p2align 4
+@rust_psm_stack_pointer@0:
+/* extern "fastcall" fn() -> *mut u8 (%rax) */
+.cfi_startproc
+ leal 4(%esp), %eax
+ retl
+.cfi_endproc
+
+
+.def @rust_psm_replace_stack@16
+.scl 2
+.type 32
+.endef
+.globl @rust_psm_replace_stack@16
+.p2align 4
+@rust_psm_replace_stack@16:
+/* extern "fastcall" fn(%ecx: usize, %edx: extern "fastcall" fn(usize), 4(%esp): *mut u8) */
+.cfi_startproc
+/*
+ All we gotta do is set the stack pointer to 4(%esp) & tail-call the callback in %edx
+
+ Note, that the callee expects the stack to be offset by 4 bytes (normally, a return address
+ would be store there) off the required stack alignment on entry. To offset the stack in such a
+ way we use the `calll` instruction, however it would also be possible to to use plain `jmpl` but
+ would require to adjust the stack manually, which cannot be easily done, because the stack
+ pointer argument is already stored in memory.
+ */
+ movl 8(%esp), %eax
+ mov %eax, %fs:0x08
+ movl 4(%esp), %esp
+ mov %esp, %fs:0x04
+ calll *%edx
+ ud2
+.cfi_endproc
+
+
+.def @rust_psm_on_stack@16
+.scl 2
+.type 32
+.endef
+.globl @rust_psm_on_stack@16
+.p2align 4
+@rust_psm_on_stack@16:
+/* extern "fastcall" fn(%ecx: usize, %edx: usize, 4(%esp): extern "fastcall" fn(usize, usize), 8(%esp): *mut u8) */
+.cfi_startproc
+ pushl %ebp
+ .cfi_def_cfa %esp, 8
+ .cfi_offset %ebp, -8
+ pushl %fs:0x04
+ .cfi_def_cfa %esp, 12
+ pushl %fs:0x08
+ .cfi_def_cfa %esp, 16
+ movl %esp, %ebp
+ .cfi_def_cfa_register %ebp
+
+ movl 24(%ebp), %eax
+ movl %eax, %fs:0x08
+ movl 20(%ebp), %esp
+ movl %esp, %fs:0x04
+ calll *16(%ebp)
+
+ movl %ebp, %esp
+ popl %fs:0x08
+ .cfi_def_cfa %esp, 12
+ popl %fs:0x04
+ .cfi_def_cfa %esp, 8
+ popl %ebp
+ .cfi_def_cfa %esp, 4
+ retl $12
+.cfi_endproc
+
diff --git a/vendor/psm/src/arch/zseries_linux.s b/vendor/psm/src/arch/zseries_linux.s
new file mode 100644
index 000000000..e2536a1c9
--- /dev/null
+++ b/vendor/psm/src/arch/zseries_linux.s
@@ -0,0 +1,75 @@
+/* Implementation of stack swtiching routines for zSeries LINUX ABI.
+
+ This ABI is used by the s390x-unknown-linux-gnu target.
+
+ Documents used:
+
+ * LINUX for zSeries: ELF Application Binary Interface Supplement (1st ed., 2001) (LNUX-1107-01)
+ * z/Architecture: Principles of Operation (4th ed., 2004) (SA22-7832-03)
+*/
+
+#include "psm.h"
+
+.text
+
+
+.globl rust_psm_stack_direction
+.p2align 4
+.type rust_psm_stack_direction,@function
+rust_psm_stack_direction:
+/* extern "C" fn() -> u8 */
+.cfi_startproc
+ lghi %r2, STACK_DIRECTION_DESCENDING
+ br %r14
+.rust_psm_stack_direction_end:
+.size rust_psm_stack_direction,.rust_psm_stack_direction_end-rust_psm_stack_direction
+.cfi_endproc
+
+
+.globl rust_psm_stack_pointer
+.p2align 4
+.type rust_psm_stack_pointer,@function
+rust_psm_stack_pointer:
+/* extern "C" fn() -> *mut u8 */
+.cfi_startproc
+ la %r2, 0(%r15)
+ br %r14
+.rust_psm_stack_pointer_end:
+.size rust_psm_stack_pointer,.rust_psm_stack_pointer_end-rust_psm_stack_pointer
+.cfi_endproc
+
+
+.globl rust_psm_replace_stack
+.p2align 4
+.type rust_psm_replace_stack,@function
+rust_psm_replace_stack:
+/* extern "C" fn(r2: usize, r3: extern "C" fn(usize), r4: *mut u8) */
+.cfi_startproc
+ /* FIXME: backtrace does not terminate cleanly for some reason */
+ lay %r15, -160(%r4)
+ /* FIXME: this is `basr` instead of `br` purely to remove the backtrace link to the caller */
+ basr %r14, %r3
+.rust_psm_replace_stack_end:
+.size rust_psm_replace_stack,.rust_psm_replace_stack_end-rust_psm_replace_stack
+.cfi_endproc
+
+
+.globl rust_psm_on_stack
+.p2align 4
+.type rust_psm_on_stack,@function
+rust_psm_on_stack:
+/* extern "C" fn(r2: usize, r3: usize, r4: extern "C" fn(usize, usize), r5: *mut u8) */
+.cfi_startproc
+ stmg %r14, %r15, -16(%r5)
+ lay %r15, -176(%r5)
+ .cfi_def_cfa %r15, 176
+ .cfi_offset %r14, -16
+ .cfi_offset %r15, -8
+ basr %r14, %r4
+ lmg %r14, %r15, 160(%r15)
+ .cfi_restore %r14
+ .cfi_restore %r15
+ br %r14
+.rust_psm_on_stack_end:
+.size rust_psm_on_stack,.rust_psm_on_stack_end-rust_psm_on_stack
+.cfi_endproc
diff --git a/vendor/psm/src/lib.rs b/vendor/psm/src/lib.rs
new file mode 100644
index 000000000..61ab9a85b
--- /dev/null
+++ b/vendor/psm/src/lib.rs
@@ -0,0 +1,406 @@
+//! # **P**ortable **S**tack **M**anipulation
+//! This crate provides portable functions to control the stack pointer and inspect the properties
+//! of the stack. This crate does not attempt to provide safe abstractions to any operations, the
+//! only goals are correctness, portability and efficiency (in that exact order). As a consequence
+//! most functions you will find in this crate are unsafe.
+//!
+//! Note, that the stack allocation is left up to the user. Unless you’re writing a safe
+//! abstraction over stack manipulation, this is unlikely to be the crate you want. Instead
+//! consider one of the safe abstractions over this crate such as `stacker`. Another good place to
+//! look at is the crates.io’s reverse dependency list.
+
+#![allow(unused_macros)]
+#![no_std]
+
+macro_rules! extern_item {
+ (unsafe $($toks: tt)+) => {
+ unsafe extern "C" $($toks)+
+ };
+ ($($toks: tt)+) => {
+ extern "C" $($toks)+
+ };
+}
+
+// Surprising: turns out subsequent macro_rules! override previous definitions, instead of
+// erroring? Convenient for us in this case, though.
+#[cfg(target_arch = "x86_64")]
+macro_rules! extern_item {
+ (unsafe $($toks: tt)+) => {
+ unsafe extern "sysv64" $($toks)+
+ };
+ ($($toks: tt)+) => {
+ extern "sysv64" $($toks)+
+ };
+}
+
+#[cfg(target_arch = "x86")]
+macro_rules! extern_item {
+ (unsafe $($toks: tt)+) => {
+ unsafe extern "fastcall" $($toks)+
+ };
+ ($($toks: tt)+) => {
+ extern "fastcall" $($toks)+
+ };
+}
+
+#[cfg(target_arch = "arm")]
+macro_rules! extern_item {
+ (unsafe $($toks: tt)+) => {
+ unsafe extern "aapcs" $($toks)+
+ };
+ ($($toks: tt)+) => {
+ extern "aapcs" $($toks)+
+ };
+}
+
+// NB: this could be nicer across multiple blocks but we cannot do it because of
+// https://github.com/rust-lang/rust/issues/65847
+extern_item! { {
+ #![link(name="psm_s")]
+
+ #[cfg(asm)]
+ fn rust_psm_stack_direction() -> u8;
+ #[cfg(asm)]
+ fn rust_psm_stack_pointer() -> *mut u8;
+
+ #[cfg(all(switchable_stack, not(target_os = "windows")))]
+ #[link_name="rust_psm_replace_stack"]
+ fn _rust_psm_replace_stack(
+ data: usize,
+ callback: extern_item!(unsafe fn(usize) -> !),
+ sp: *mut u8
+ ) -> !;
+ #[cfg(all(switchable_stack, not(target_os = "windows")))]
+ #[link_name="rust_psm_on_stack"]
+ fn _rust_psm_on_stack(
+ data: usize,
+ return_ptr: usize,
+ callback: extern_item!(unsafe fn(usize, usize)),
+ sp: *mut u8,
+ );
+ #[cfg(all(switchable_stack, target_os = "windows"))]
+ fn rust_psm_replace_stack(
+ data: usize,
+ callback: extern_item!(unsafe fn(usize) -> !),
+ sp: *mut u8,
+ stack_base: *mut u8
+ ) -> !;
+ #[cfg(all(switchable_stack, target_os = "windows"))]
+ fn rust_psm_on_stack(
+ data: usize,
+ return_ptr: usize,
+ callback: extern_item!(unsafe fn(usize, usize)),
+ sp: *mut u8,
+ stack_base: *mut u8
+ );
+} }
+
+#[cfg(all(switchable_stack, not(target_os = "windows")))]
+#[inline(always)]
+unsafe fn rust_psm_replace_stack(
+ data: usize,
+ callback: extern_item!(unsafe fn(usize) -> !),
+ sp: *mut u8,
+ _: *mut u8,
+) -> ! {
+ _rust_psm_replace_stack(data, callback, sp)
+}
+
+#[cfg(all(switchable_stack, not(target_os = "windows")))]
+#[inline(always)]
+unsafe fn rust_psm_on_stack(
+ data: usize,
+ return_ptr: usize,
+ callback: extern_item!(unsafe fn(usize, usize)),
+ sp: *mut u8,
+ _: *mut u8,
+) {
+ _rust_psm_on_stack(data, return_ptr, callback, sp)
+}
+
+/// Run the closure on the provided stack.
+///
+/// Once the closure completes its execution, the original stack pointer is restored and execution
+/// returns to the caller.
+///
+/// `base` address must be the low address of the stack memory region, regardless of the stack
+/// growth direction. It is not necessary for the whole region `[base; base + size]` to be usable
+/// at the time this function called, however it is required that at least the following hold:
+///
+/// * Both `base` and `base + size` are aligned up to the target-specific requirements;
+/// * Depending on `StackDirection` value for the platform, the end of the stack memory region,
+/// which would end up containing the first frame(s), must have sufficient number of pages
+/// allocated to execute code until more pages are commited. The other end should contain a guard
+/// page (not writable, readable or executable) to ensure Rust’s soundness guarantees.
+///
+/// Note, that some or all of these considerations are irrelevant to some applications. For
+/// example, Rust’s soundness story relies on all stacks having a guard-page, however if the user
+/// is able to guarantee that the memory region used for stack cannot be exceeded, a guard page may
+/// end up being an expensive unnecessity.
+///
+/// The previous stack may not be deallocated. If an ability to deallocate the old stack is desired
+/// consider `replace_stack` instead.
+///
+/// # Guidelines
+///
+/// Memory regions that are aligned to a single page (usually 4kB) are an extremely portable choice
+/// for stacks.
+///
+/// Allocate at least 4kB of stack. Some architectures (such as SPARC) consume stack memory
+/// significantly faster compared to the more usual architectures such as x86 or ARM. Allocating
+/// less than 4kB of memory may make it impossible to commit more pages without overflowing the
+/// stack later on.
+///
+/// # Unsafety
+///
+/// The stack `base` address must be aligned as appropriate for the target.
+///
+/// The stack `size` must be a multiple of stack alignment required by target.
+///
+/// The `size` must not overflow `isize`.
+///
+/// `callback` must not unwind or return control flow by any other means than directly returning.
+///
+/// # Examples
+///
+/// ```
+/// use std::alloc;
+/// const STACK_ALIGN: usize = 4096;
+/// const STACK_SIZE: usize = 4096;
+/// unsafe {
+/// let layout = alloc::Layout::from_size_align(STACK_SIZE, STACK_ALIGN).unwrap();
+/// let new_stack = alloc::alloc(layout);
+/// assert!(!new_stack.is_null(), "allocations must succeed!");
+/// let (stack, result) = psm::on_stack(new_stack, STACK_SIZE, || {
+/// (psm::stack_pointer(), 4 + 4)
+/// });
+/// println!("4 + 4 = {} has been calculated on stack {:p}", result, stack);
+/// }
+/// ```
+#[cfg(switchable_stack)]
+pub unsafe fn on_stack<R, F: FnOnce() -> R>(base: *mut u8, size: usize, callback: F) -> R {
+ use core::mem::MaybeUninit;
+
+ extern_item! {
+ unsafe fn with_on_stack<R, F: FnOnce() -> R>(callback_ptr: usize, return_ptr: usize) {
+ let return_ptr = (*(return_ptr as *mut MaybeUninit<R>)).as_mut_ptr();
+ let callback = (*(callback_ptr as *mut MaybeUninit<F>)).as_ptr();
+ // Safe to move out from `F`, because closure in is forgotten in `on_stack` and dropping
+ // only occurs in this callback.
+ return_ptr.write((callback.read())());
+ }
+ }
+ let sp = match StackDirection::new() {
+ StackDirection::Ascending => base,
+ StackDirection::Descending => base.offset(size as isize),
+ };
+ let mut callback: MaybeUninit<F> = MaybeUninit::new(callback);
+ let mut return_value: MaybeUninit<R> = MaybeUninit::uninit();
+ rust_psm_on_stack(
+ &mut callback as *mut MaybeUninit<F> as usize,
+ &mut return_value as *mut MaybeUninit<R> as usize,
+ with_on_stack::<R, F>,
+ sp,
+ base,
+ );
+ return return_value.assume_init();
+}
+
+/// Run the provided non-terminating computation on an entirely new stack.
+///
+/// `base` address must be the low address of the stack memory region, regardless of the stack
+/// growth direction. It is not necessary for the whole region `[base; base + size]` to be usable
+/// at the time this function called, however it is required that at least the following hold:
+///
+/// * Both `base` and `base + size` are aligned up to the target-specific requirements;
+/// * Depending on `StackDirection` value for the platform, the end of the stack memory region,
+/// which would end up containing the first frame(s), must have sufficient number of pages
+/// allocated to execute code until more pages are commited. The other end should contain a guard
+/// page (not writable, readable or executable) to ensure Rust’s soundness guarantees.
+///
+/// Note, that some or all of these considerations are irrelevant to some applications. For
+/// example, Rust’s soundness story relies on all stacks having a guard-page, however if the user
+/// is able to guarantee that the memory region used for stack cannot be exceeded, a guard page may
+/// end up being an expensive unnecessity.
+///
+/// The previous stack is not deallocated and may not be deallocated unless the data on the old
+/// stack is not referenced in any way (by e.g. the `callback` closure).
+///
+/// On platforms where multiple stack pointers are available, the “current” stack pointer is
+/// replaced.
+///
+/// # Guidelines
+///
+/// Memory regions that are aligned to a single page (usually 4kB) are an extremely portable choice
+/// for stacks.
+///
+/// Allocate at least 4kB of stack. Some architectures (such as SPARC) consume stack memory
+/// significantly faster compared to the more usual architectures such as x86 or ARM. Allocating
+/// less than 4kB of memory may make it impossible to commit more pages without overflowing the
+/// stack later on.
+///
+/// # Unsafety
+///
+/// The stack `base` address must be aligned as appropriate for the target.
+///
+/// The stack `size` must be a multiple of stack alignment required by target.
+///
+/// The `size` must not overflow `isize`.
+///
+/// `callback` must not return (not enforced by typesystem currently because `!` is unstable),
+/// unwind or otherwise return control flow to any of the previous frames.
+#[cfg(switchable_stack)]
+pub unsafe fn replace_stack<F: FnOnce()>(base: *mut u8, size: usize, callback: F) -> ! {
+ extern_item! { unsafe fn with_replaced_stack<F: FnOnce()>(d: usize) -> ! {
+ // Safe to move out, because the closure is essentially forgotten by
+ // this being required to never return...
+ ::core::ptr::read(d as *const F)();
+ ::core::hint::unreachable_unchecked();
+ } }
+ let sp = match StackDirection::new() {
+ StackDirection::Ascending => base,
+ StackDirection::Descending => base.offset(size as isize),
+ };
+ rust_psm_replace_stack(
+ &callback as *const F as usize,
+ with_replaced_stack::<F>,
+ sp,
+ base,
+ );
+}
+
+/// The direction into which stack grows as stack frames are made.
+///
+/// This is a target-specific property that can be obtained at runtime by calling
+/// `StackDirection::new()`.
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum StackDirection {
+ Ascending = 1,
+ Descending = 2,
+}
+
+impl StackDirection {
+ /// Obtain the stack growth direction.
+ #[cfg(asm)]
+ pub fn new() -> StackDirection {
+ const ASC: u8 = StackDirection::Ascending as u8;
+ const DSC: u8 = StackDirection::Descending as u8;
+ unsafe {
+ match rust_psm_stack_direction() {
+ ASC => StackDirection::Ascending,
+ DSC => StackDirection::Descending,
+ _ => ::core::hint::unreachable_unchecked(),
+ }
+ }
+ }
+}
+
+/// Returns current stack pointer.
+///
+/// Note, that the stack pointer returned is from the perspective of the caller. From the
+/// perspective of `stack_pointer` function the pointer returned is the frame pointer.
+///
+/// While it is a goal to minimize the amount of stack used by this function, implementations for
+/// some targets may be unable to avoid allocating a stack frame. This makes this function
+/// suitable for stack exhaustion detection only in conjunction with sufficient padding.
+///
+/// Using `stack_pointer` to check for stack exhaustion is tricky to get right. It is impossible to
+/// know the callee’s frame size, therefore such value must be derived some other way. A common
+/// approach is to use stack padding (reserve enough stack space for any function to be called) and
+/// check against the padded threshold. If padding is chosen incorrectly, a situation similar to
+/// one described below may occur:
+///
+/// 1. For stack exhaustion check, remaining stack is checked against `stack_pointer` with the
+/// padding applied;
+/// 2. Callee allocates more stack than was accounted for with padding, and accesses pages outside
+/// the stack, invalidating the execution (by e.g. crashing).
+#[cfg(asm)]
+pub fn stack_pointer() -> *mut u8 {
+ unsafe { rust_psm_stack_pointer() }
+}
+
+/// Macro that outputs its tokens only if `psm::on_stack` and `psm::replace_stack` are available.
+///
+/// # Examples
+///
+/// ```
+/// # use psm::psm_stack_manipulation;
+/// psm_stack_manipulation! {
+/// yes {
+/// /* Functions `on_stack` and `replace_stack` are available here */
+/// }
+/// no {
+/// /* Functions `on_stack` and `replace_stack` are not available here */
+/// }
+/// }
+/// ```
+#[cfg(switchable_stack)]
+#[macro_export]
+macro_rules! psm_stack_manipulation {
+ (yes { $($yes: tt)* } no { $($no: tt)* }) => { $($yes)* };
+}
+
+/// Macro that outputs its tokens only if `psm::on_stack` and `psm::replace_stack` are available.
+///
+/// # Examples
+///
+/// ```
+/// # use psm::psm_stack_manipulation;
+/// psm_stack_manipulation! {
+/// yes {
+/// /* Functions `on_stack` and `replace_stack` are available here */
+/// }
+/// no {
+/// /* Functions `on_stack` and `replace_stack` are not available here */
+/// }
+/// }
+/// ```
+#[cfg(not(switchable_stack))]
+#[macro_export]
+macro_rules! psm_stack_manipulation {
+ (yes { $($yes: tt)* } no { $($no: tt)* }) => { $($no)* };
+}
+
+/// Macro that outputs its tokens only if `psm::stack_pointer` and `psm::StackDirection::new` are
+/// available.
+///
+/// # Examples
+///
+/// ```
+/// # use psm::psm_stack_information;
+/// psm_stack_information! {
+/// yes {
+/// /* `psm::stack_pointer` and `psm::StackDirection::new` are available here */
+/// }
+/// no {
+/// /* `psm::stack_pointer` and `psm::StackDirection::new` are not available here */
+/// }
+/// }
+/// ```
+#[cfg(asm)]
+#[macro_export]
+macro_rules! psm_stack_information {
+ (yes { $($yes: tt)* } no { $($no: tt)* }) => { $($yes)* };
+}
+
+/// Macro that outputs its tokens only if `psm::stack_pointer` and `psm::StackDirection::new` are
+/// available.
+///
+/// # Examples
+///
+/// ```
+/// # use psm::psm_stack_information;
+/// psm_stack_information! {
+/// yes {
+/// /* `psm::stack_pointer` and `psm::StackDirection::new` are available here */
+/// }
+/// no {
+/// /* `psm::stack_pointer` and `psm::StackDirection::new` are not available here */
+/// }
+/// }
+/// ```
+#[cfg(not(asm))]
+#[macro_export]
+macro_rules! psm_stack_information {
+ (yes { $($yes: tt)* } no { $($no: tt)* }) => { $($no)* };
+}