// 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" #define real4 dword #define real8 qword // // file: profile.cpp // typedef struct _PROFILE_PLATFORM_SPECIFIC_DATA // { // FunctionID *functionId; // function ID comes in the r11 register // void *rbp; // void *probersp; // void *ip; // void *profiledRsp; // UINT64 rax; // LPVOID hiddenArg; // UINT64 flt0; // UINT64 flt1; // UINT64 flt2; // UINT64 flt3; // UINT64 flt4; // UINT64 flt5; // UINT64 flt6; // UINT64 flt7; // UINT64 rdi; // UINT64 rsi; // UINT64 rdx; // UINT64 rcx; // UINT64 r8; // UINT64 r9; // UINT32 flags; // } PROFILE_PLATFORM_SPECIFIC_DATA, *PPROFILE_PLATFORM_SPECIFIC_DATA; // .equ SIZEOF_PROFILE_PLATFORM_SPECIFIC_DATA, 0x8*22 + 0x8 // includes fudge to make FP_SPILL right .equ SIZEOF_FP_ARG_SPILL, 0x10*2 .equ SIZEOF_STACK_FRAME, SIZEOF_PROFILE_PLATFORM_SPECIFIC_DATA + SIZEOF_FP_ARG_SPILL .equ PROFILE_ENTER, 0x1 .equ PROFILE_LEAVE, 0x2 .equ PROFILE_TAILCALL, 0x4 // *********************************************************** // NOTE: // // Register preservation scheme: // // Preserved: // - all non-volatile registers // - rax, rdx // - xmm0, xmm1 // // Not Preserved: // - integer argument registers (rcx, rdx, r8, r9) // - floating point argument registers (xmm1-3) // - volatile integer registers (r10, r11) // - volatile floating point registers (xmm4-5) // - upper halves of ymm registers on AVX (which are volatile) // // *********************************************************** // EXTERN_C void ProfileEnterNaked(FunctionIDOrClientID functionIDOrClientID, size_t profiledRsp); // // // NESTED_ENTRY ProfileEnterNaked, _TEXT, NoHandler // Upon entry : // r14 = clientInfo // r15 = profiledRsp push_nonvol_reg rax lea rax, [rsp + 0x10] // caller rsp mov r10, [rax - 0x8] // return address push_argument_register rdx alloc_stack SIZEOF_STACK_FRAME // correctness of return value in structure doesn't matter for enter probe // setup ProfilePlatformSpecificData structure xor r11, r11 // nullify r11 mov [rsp + 0x0], r11 // r11 is null -- struct functionId field save_reg_postrsp rbp, 0x8 // -- struct rbp field mov [rsp + 0x10], rax // caller rsp -- struct probeRsp field mov [rsp + 0x18], r10 // return address -- struct ip field mov [rsp + 0x20], r15 // -- struct profiledRsp field mov [rsp + 0x28], r11 // return value -- struct rax field mov [rsp + 0x30], r11 // r11 is null -- struct hiddenArg field movsd real8 ptr [rsp + 0x38], xmm0 // -- struct flt0 field movsd real8 ptr [rsp + 0x40], xmm1 // -- struct flt1 field movsd real8 ptr [rsp + 0x48], xmm2 // -- struct flt2 field movsd real8 ptr [rsp + 0x50], xmm3 // -- struct flt3 field movsd real8 ptr [rsp + 0x58], xmm4 // -- struct flt4 field movsd real8 ptr [rsp + 0x60], xmm5 // -- struct flt5 field movsd real8 ptr [rsp + 0x68], xmm6 // -- struct flt6 field movsd real8 ptr [rsp + 0x70], xmm7 // -- struct flt7 field mov [rsp + 0x78], rdi // -- struct rdi field mov [rsp + 0x80], rsi // -- struct rsi field mov [rsp + 0x88], rdx // -- struct rdx field mov [rsp + 0x90], rcx // -- struct rcx field mov [rsp + 0x98], r8 // -- struct r8 field mov [rsp + 0xa0], r9 // -- struct r9 field mov r10, 0x1 // PROFILE_ENTER mov [rsp + 0xa8], r10d // -- struct flags field // get aligned stack ptr (rsp + FRAME_SIZE) & (-16) lea rax, [rsp + 0xb8] and rax, -16 // we need to be able to restore the fp return register // save fp return registers movdqa [rax + 0x00], xmm0 movdqa [rax + 0x10], xmm1 END_PROLOGUE // rdi already contains the clientInfo mov rdi, r14 lea rsi, [rsp + 0x0] call C_FUNC(ProfileEnter) // restore fp return registers lea rax, [rsp + 0xb8] and rax, -16 movdqa xmm0, [rax + 0x00] movdqa xmm1, [rax + 0x10] // restore arg registers mov rdi, [rsp + 0x78] mov rsi, [rsp + 0x80] mov rdx, [rsp + 0x88] mov rcx, [rsp + 0x90] mov r8, [rsp + 0x98] mov r9, [rsp + 0xa0] // begin epilogue free_stack SIZEOF_STACK_FRAME pop_argument_register rdx pop_nonvol_reg rax ret NESTED_END ProfileEnterNaked, _TEXT // EXTERN_C void ProfileLeaveNaked(FunctionIDOrClientID functionIDOrClientID, size_t profiledRsp); // // // NESTED_ENTRY ProfileLeaveNaked, _TEXT, NoHandler // Upon entry : // rdi = clientInfo // rsi = profiledRsp push_nonvol_reg rbx lea rbx, [rsp + 0x10] // caller rsp mov r10, [rbx - 0x8] // return address // rdx should be saved here because it can be used for returning struct values push_argument_register rdx alloc_stack SIZEOF_STACK_FRAME // correctness of argument registers in structure doesn't matter for leave probe // setup ProfilePlatformSpecificData structure xor r11, r11 // nullify r11 mov [rsp + 0x0], r11 // r11 is null -- struct functionId field save_reg_postrsp rbp, 0x8 // -- struct rbp field mov [rsp + 0x10], rbx // caller rsp -- struct probeRsp field mov [rsp + 0x18], r10 // return address -- struct ip field mov [rsp + 0x20], rsi // -- struct profiledRsp field mov [rsp + 0x28], rax // return value -- struct rax field mov [rsp + 0x30], r11 // r11 is null -- struct hiddenArg field movsd real8 ptr [rsp + 0x38], xmm0 // -- struct flt0 field movsd real8 ptr [rsp + 0x40], xmm1 // -- struct flt1 field movsd real8 ptr [rsp + 0x48], xmm2 // -- struct flt2 field movsd real8 ptr [rsp + 0x50], xmm3 // -- struct flt3 field movsd real8 ptr [rsp + 0x58], xmm4 // -- struct flt4 field movsd real8 ptr [rsp + 0x60], xmm5 // -- struct flt5 field movsd real8 ptr [rsp + 0x68], xmm6 // -- struct flt6 field movsd real8 ptr [rsp + 0x70], xmm7 // -- struct flt7 field mov [rsp + 0x78], r11 // -- struct rdi field mov [rsp + 0x80], r11 // -- struct rsi field mov [rsp + 0x88], r11 // -- struct rdx field mov [rsp + 0x90], r11 // -- struct rcx field mov [rsp + 0x98], r11 // -- struct r8 field mov [rsp + 0xa0], r11 // -- struct r9 field mov r10, 0x2 // PROFILE_LEAVE mov [rsp + 0xa8], r10d // flags -- struct flags field // get aligned stack ptr (rsp + FRAME_SIZE) & (-16) lea rax, [rsp + 0xb8] and rax, -16 // we need to be able to restore the fp return register // save fp return registers movdqa [rax + 0x00], xmm0 movdqa [rax + 0x10], xmm1 END_PROLOGUE // rdi already contains the clientInfo lea rsi, [rsp + 0x0] call C_FUNC(ProfileLeave) // restore fp return registers lea rax, [rsp + 0xb8] and rax, -16 movdqa xmm0, [rax + 0x00] movdqa xmm1, [rax + 0x10] // restore int return register mov rax, [rsp + 0x28] // begin epilogue free_stack SIZEOF_STACK_FRAME pop_argument_register rdx pop_nonvol_reg rbx ret NESTED_END ProfileLeaveNaked, _TEXT // EXTERN_C void ProfileTailcallNaked(FunctionIDOrClientID functionIDOrClientID, size_t profiledRsp); // // // NESTED_ENTRY ProfileTailcallNaked, _TEXT, NoHandler // Upon entry : // rdi = clientInfo // rsi = profiledRsp push_nonvol_reg rbx lea rbx, [rsp + 0x10] // caller rsp mov r10, [rbx - 0x8] // return address // rdx should be saved here because it can be used for returning struct values push_argument_register rdx alloc_stack SIZEOF_STACK_FRAME // correctness of argument registers in structure doesn't matter for tailcall probe // setup ProfilePlatformSpecificData structure xor r11, r11 // nullify r11 mov [rsp + 0x0], r11 // r11 is null -- struct functionId field save_reg_postrsp rbp, 0x8 // -- struct rbp field mov [rsp + 0x10], rbx // caller rsp -- struct probeRsp field mov [rsp + 0x18], r10 // return address -- struct ip field mov [rsp + 0x20], rsi // -- struct profiledRsp field mov [rsp + 0x28], rax // return value -- struct rax field mov [rsp + 0x30], r11 // r11 is null -- struct hiddenArg field movsd real8 ptr [rsp + 0x38], xmm0 // -- struct flt0 field movsd real8 ptr [rsp + 0x40], xmm1 // -- struct flt1 field movsd real8 ptr [rsp + 0x48], xmm2 // -- struct flt2 field movsd real8 ptr [rsp + 0x50], xmm3 // -- struct flt3 field movsd real8 ptr [rsp + 0x58], xmm4 // -- struct flt4 field movsd real8 ptr [rsp + 0x60], xmm5 // -- struct flt5 field movsd real8 ptr [rsp + 0x68], xmm6 // -- struct flt6 field movsd real8 ptr [rsp + 0x70], xmm7 // -- struct flt7 field mov [rsp + 0x78], r11 // -- struct rdi field mov [rsp + 0x80], r11 // -- struct rsi field mov [rsp + 0x88], r11 // -- struct rdx field mov [rsp + 0x90], r11 // -- struct rcx field mov [rsp + 0x98], r11 // -- struct r8 field mov [rsp + 0xa0], r11 // -- struct r9 field mov r10, 0x2 // PROFILE_LEAVE mov [rsp + 0xa8], r10d // flags -- struct flags field // get aligned stack ptr (rsp + FRAME_SIZE) & (-16) lea rax, [rsp + 0xc0] and rax, -16 // we need to be able to restore the fp return register // save fp return registers movdqa [rax + 0x00], xmm0 movdqa [rax + 0x10], xmm1 END_PROLOGUE // rdi already contains the clientInfo lea rsi, [rsp + 0x0] call C_FUNC(ProfileTailcall) // restore fp return registers lea rax, [rsp + 0xc0] and rax, -16 movdqa xmm0, [rax + 0x00] movdqa xmm1, [rax + 0x10] // restore int return register mov rax, [rsp + 0x28] // begin epilogue free_stack SIZEOF_STACK_FRAME pop_argument_register rdx pop_nonvol_reg rbx ret NESTED_END ProfileTailcallNaked, _TEXT