summaryrefslogtreecommitdiff
path: root/src/vm/amd64/unixasmhelpers.S
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/amd64/unixasmhelpers.S')
-rw-r--r--src/vm/amd64/unixasmhelpers.S231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/vm/amd64/unixasmhelpers.S b/src/vm/amd64/unixasmhelpers.S
new file mode 100644
index 0000000000..3cf69fb649
--- /dev/null
+++ b/src/vm/amd64/unixasmhelpers.S
@@ -0,0 +1,231 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.intel_syntax noprefix
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// PrecodeFixupThunk
+//
+// The call in fixup precode initally points to this function.
+// The pupose of this function is to load the MethodDesc and forward the call the prestub.
+//
+// EXTERN_C VOID __stdcall PrecodeFixupThunk()
+LEAF_ENTRY PrecodeFixupThunk, _TEXT
+
+ pop rax // Pop the return address. It points right after the call instruction in the precode.
+
+ // Inline computation done by FixupPrecode::GetMethodDesc()
+ movzx r10,byte ptr [rax+2] // m_PrecodeChunkIndex
+ movzx r11,byte ptr [rax+1] // m_MethodDescChunkIndex
+ mov rax,qword ptr [rax+r10*8+3]
+ lea METHODDESC_REGISTER,[rax+r11*8]
+
+ // Tail call to prestub
+ jmp C_FUNC(ThePreStub)
+
+LEAF_END PrecodeFixupThunk, _TEXT
+
+// EXTERN_C int __fastcall HelperMethodFrameRestoreState(
+// INDEBUG_COMMA(HelperMethodFrame *pFrame)
+// MachState *pState
+// )
+LEAF_ENTRY HelperMethodFrameRestoreState, _TEXT
+
+#ifdef _DEBUG
+ mov rdi, rsi
+#endif
+
+ // Check if the MachState is valid
+ xor eax, eax
+ cmp qword ptr [rdi + OFFSETOF__MachState___pRetAddr], rax
+ jne DoRestore
+ REPRET
+DoRestore:
+
+ //
+ // If a preserved register were pushed onto the stack between
+ // the managed caller and the H_M_F, m_pReg will point to its
+ // location on the stack and it would have been updated on the
+ // stack by the GC already and it will be popped back into the
+ // appropriate register when the appropriate epilog is run.
+ //
+ // Otherwise, the register is preserved across all the code
+ // in this HCALL or FCALL, so we need to update those registers
+ // here because the GC will have updated our copies in the
+ // frame.
+ //
+ // So, if m_pReg points into the MachState, we need to update
+ // the register here. That's what this macro does.
+ //
+#define RestoreReg(reg, regnum) \
+ lea rax, [rdi + OFFSETOF__MachState__m_Capture + 8 * regnum]; \
+ mov rdx, [rdi + OFFSETOF__MachState__m_Ptrs + 8 * regnum]; \
+ cmp rax, rdx; \
+ cmove reg, [rax];
+
+ // regnum has to match ENUM_CALLEE_SAVED_REGISTERS macro
+ RestoreReg(R12, 0)
+ RestoreReg(R13, 1)
+ RestoreReg(R14, 2)
+ RestoreReg(R15, 3)
+ RestoreReg(Rbx, 4)
+ RestoreReg(Rbp, 5)
+
+ xor eax, eax
+ ret
+
+LEAF_END HelperMethodFrameRestoreState, _TEXT
+
+//////////////////////////////////////////////////////////////////////////
+//
+// NDirectImportThunk
+//
+// In addition to being called by the EE, this function can be called
+// directly from code generated by JIT64 for CRT optimized direct
+// P/Invoke calls. If it is modified, the JIT64 compiler's code
+// generation will need to altered accordingly.
+//
+// EXTERN_C VOID __stdcall NDirectImportThunk()//
+NESTED_ENTRY NDirectImportThunk, _TEXT, NoHandler
+
+ //
+ // Save integer parameter registers.
+ // Make sure to preserve r11 as well as it is used to pass the stack argument size from JIT
+ //
+ PUSH_ARGUMENT_REGISTERS
+ push_register r11
+
+ //
+ // Allocate space for XMM parameter registers
+ //
+ alloc_stack 0x80
+
+ SAVE_FLOAT_ARGUMENT_REGISTERS 0
+
+ END_PROLOGUE
+
+ //
+ // Call NDirectImportWorker w/ the NDirectMethodDesc*
+ //
+ mov rdi, METHODDESC_REGISTER
+ call C_FUNC(NDirectImportWorker)
+
+ RESTORE_FLOAT_ARGUMENT_REGISTERS 0
+
+ //
+ // epilogue, rax contains the native target address
+ //
+ free_stack 0x80
+
+ //
+ // Restore integer parameter registers and r11
+ //
+ pop_register r11
+ POP_ARGUMENT_REGISTERS
+
+ TAILJMP_RAX
+NESTED_END NDirectImportThunk, _TEXT
+
+// EXTERN_C void moveOWord(LPVOID* src, LPVOID* target);
+// <NOTE>
+// MOVDQA is not an atomic operation. You need to call this function in a crst.
+// </NOTE>
+LEAF_ENTRY moveOWord, _TEXT
+ movdqu xmm0, xmmword ptr [rdi]
+ movdqu xmmword ptr [rsi], xmm0
+
+ ret
+LEAF_END moveOWord, _TEXT
+
+//------------------------------------------------
+// JIT_RareDisableHelper
+//
+// The JIT expects this helper to preserve registers used for return values
+//
+NESTED_ENTRY JIT_RareDisableHelper, _TEXT, NoHandler
+
+ // First integer return register
+ push_register rax
+ // Second integer return register
+ push_register rdx
+ alloc_stack 0x28
+ END_PROLOGUE
+ // First float return register
+ movdqa xmmword ptr [rsp], xmm0
+ // Second float return register
+ movdqa xmmword ptr [rsp+0x10], xmm1
+
+ call C_FUNC(JIT_RareDisableHelperWorker)
+
+ movdqa xmm0, xmmword ptr [rsp]
+ movdqa xmm1, xmmword ptr [rsp+0x10]
+ free_stack 0x28
+ pop_register rdx
+ pop_register rax
+ ret
+
+NESTED_END JIT_RareDisableHelper, _TEXT
+
+#ifdef FEATURE_HIJACK
+
+//------------------------------------------------
+// OnHijackTripThread
+//
+NESTED_ENTRY OnHijackTripThread, _TEXT, NoHandler
+
+ // Make room for the real return address (rip)
+ push_register rax
+
+ PUSH_CALLEE_SAVED_REGISTERS
+
+ push_register rdx
+ // Push rax again - this is where integer/pointer return values are returned
+ push_register rax
+
+ mov rdi, rsp
+
+ alloc_stack 0x28
+
+ // First float return register
+ movdqa [rsp], xmm0
+ // Second float return register
+ movdqa [rsp+0x10], xmm1
+
+ END_PROLOGUE
+
+ call C_FUNC(OnHijackWorker)
+
+ movdqa xmm0, [rsp]
+ movdqa xmm1, [rsp+0x10]
+ free_stack 0x28
+ pop_register rax
+ pop_register rdx
+
+ POP_CALLEE_SAVED_REGISTERS
+ ret
+
+NESTED_END OnHijackTripThread, _TEXT
+
+#endif // FEATURE_HIJACK
+
+LEAF_ENTRY SinglecastDelegateInvokeStub, _TEXT
+
+ test rdi, rdi
+ jz NullObject
+
+
+ mov rax, [rdi + OFFSETOF__DelegateObject___methodPtr]
+ mov rdi, [rdi + OFFSETOF__DelegateObject___target] // replace "this" pointer
+
+ jmp rax
+
+NullObject:
+ mov rdi, CORINFO_NullReferenceException_ASM
+ jmp C_FUNC(JIT_InternalThrow)
+
+LEAF_END SinglecastDelegateInvokeStub, _TEXT