diff options
Diffstat (limited to 'rts/adjustor/NativeAmd64MingwAsm.S')
-rw-r--r-- | rts/adjustor/NativeAmd64MingwAsm.S | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/rts/adjustor/NativeAmd64MingwAsm.S b/rts/adjustor/NativeAmd64MingwAsm.S new file mode 100644 index 0000000000..ae80f9b86b --- /dev/null +++ b/rts/adjustor/NativeAmd64MingwAsm.S @@ -0,0 +1,140 @@ +#include "include/ghcconfig.h" + +#define HPTR_OFF 0 +#define WPTR_OFF 8 + +#if defined(LEADING_UNDERSCORE) +#define CSYM(x) _ ## x +#else +#define CSYM(x) x +#endif + +#define DECLARE_CSYM(x) \ + .globl CSYM(x) ; \ + CSYM(x): + +/* ------------------------------------------------------------------ + * Adjustor for a call with less than 4 integer arguments. + * ------------------------------------------------------------------ */ +DECLARE_CSYM(simple_ccall_adjustor) + // Shuffle the argument registers down + mov %r8, %r9 + mov %rdx, %r8 + mov %rcx, %rdx + movsd %xmm2, %xmm3 + movsd %xmm1, %xmm2 + movsd %xmm0, %xmm1 + mov lcl_simple_ccall_adjustor_context(%rip), %rax // load the address of the context + mov HPTR_OFF(%rax), %rcx // load the StablePtr + jmp *WPTR_OFF(%rax) // jump to the entrypoint + +.align 8 +DECLARE_CSYM(simple_ccall_adjustor_context) +// See Note [Adjustors: Local symbol references] in NativeAmd64Asm.S +lcl_simple_ccall_adjustor_context: + // this will be overwritten with a pointer to the AdjustorContext + .quad 0 +DECLARE_CSYM(simple_ccall_adjustor_end) + +/* ------------------------------------------------------------------ + * Adjustor for a call with 4 or more integer arguments and where the fourth + * argument is not floating-point. + * ------------------------------------------------------------------ */ +DECLARE_CSYM(complex_nofloat_ccall_adjustor) + sub $8,%rsp + // Handle the fourth argument; this is the only difference between the + // float/non-float cases + mov %r9, 0x20(%rsp) + // Push the new return address onto the stack + pushq complex_nofloat_ccall_ret_code_ptr(%rip) + // But the old return address has been moved up into a spill slot, so we + // need to move it above them + mov 0x10(%rsp), %r9 + mov %r9, 0x30(%rsp) + // Now do the normal argument shuffle + mov %r8, %r9 + mov %rdx, %r8 + mov %rcx, %rdx + movsd %xmm2, %xmm3 + movsd %xmm1, %xmm2 + movsd %xmm0, %xmm1 + // Load the address of the context + mov lcl_complex_nofloat_ccall_adjustor_context(%rip), %rax + mov HPTR_OFF(%rax), %rcx + jmpq *WPTR_OFF(%rax) + +.align 8 +complex_nofloat_ccall_ret_code_ptr: + .quad complex_ccall_ret_code +DECLARE_CSYM(complex_nofloat_ccall_adjustor_context) +// See Note [Adjustors: Local symbol references] in NativeAmd64Asm.S +lcl_complex_nofloat_ccall_adjustor_context: + // this will be overwritten with a pointer to the AdjustorContext + .quad 0x0 +DECLARE_CSYM(complex_nofloat_ccall_adjustor_end) + +/* ------------------------------------------------------------------ + * Adjustor for a call with 4 or more integer arguments and where the fourth + * argument is floating point. + * ------------------------------------------------------------------ */ +DECLARE_CSYM(complex_float_ccall_adjustor) + sub $8,%rsp + // Handle the fourth argument; this is the only difference between the + // float/non-float cases + movsd %xmm3,0x20(%rsp) + // Push the new return address onto the stack + pushq complex_float_ccall_ret_code_ptr(%rip) + // But the old return address has been moved up into a spill slot, so we + // need to move it above them + mov 0x10(%rsp),%r9 + mov %r9,0x30(%rsp) + // Now do the normal argument shuffle + mov %r8, %r9 + mov %rdx, %r8 + mov %rcx, %rdx + movsd %xmm2, %xmm3 + movsd %xmm1, %xmm2 + movsd %xmm0, %xmm1 + // Load the address of the context + mov complex_float_ccall_adjustor_context(%rip), %rax + mov HPTR_OFF(%rax), %rcx + jmpq *WPTR_OFF(%rax) + +.align 8 +complex_float_ccall_ret_code_ptr: + .quad complex_ccall_ret_code +DECLARE_CSYM(complex_float_ccall_adjustor_context) +// See Note [Adjustors: Local symbol references] in NativeAmd64Asm.S +lcl_complex_float_ccall_adjustor_context: + // this will be overwritten with a pointer to the AdjustorContext + .quad 0x0 +DECLARE_CSYM(complex_float_ccall_adjustor_end) + + +/* + When generating an adjustor thunk that uses the C calling + convention, we have to make sure that the thunk kicks off + the process of jumping into Haskell with a tail jump. Why? + Because as a result of jumping in into Haskell we may end + up freeing the very adjustor thunk we came from using + freeHaskellFunctionPtr(). Hence, we better not return to + the adjustor code on our way out, since it could by then + point to junk. + + The fix is readily at hand, just include the opcodes + for the C stack fixup code that we need to perform when + returning in some static piece of memory and arrange + to return to it before tail jumping from the adjustor thunk. +*/ +complex_ccall_ret_code: + addq $0x8, %rsp + /* On Win64, we had to put the original return address after the + arg 1-4 spill slots, ro now we have to move it back */ + movq 0x20(%rsp), %rcx + movq %rcx, (%rsp) + ret + +/* mark stack as nonexecutable */ +#if defined(__linux__) && defined(__ELF__) +.section .note.GNU-stack,"",@progbits +#endif |