blob: 5ecd44c0d7b5500cf37c9a0c08af14e1640cf931 [file] [log] [blame]
;/*
; Copyright (C) 2014 Apple Inc. All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions
; are met:
; 1. Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
; 2. Redistributions in binary form must reproduce the above copyright
; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution.
;
; THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
; OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;*/
PUBLIC ctiMasmProbeTrampoline
_TEXT SEGMENT
; The following constants must match the x86_64 version in MacroAssemblerX86Common.cpp.
PTR_SIZE EQU 8
PROBE_PROBE_FUNCTION_OFFSET EQU (0 * PTR_SIZE)
PROBE_ARG_OFFSET EQU (1 * PTR_SIZE)
PROBE_INIT_STACK_FUNCTION_OFFSET EQU (2 * PTR_SIZE)
PROBE_INIT_STACK_ARG_OFFSET EQU (3 * PTR_SIZE)
PROBE_FIRST_GPR_OFFSET EQU (4 * PTR_SIZE)
PROBE_CPU_EAX_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (0 * PTR_SIZE))
PROBE_CPU_ECX_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (1 * PTR_SIZE))
PROBE_CPU_EDX_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (2 * PTR_SIZE))
PROBE_CPU_EBX_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (3 * PTR_SIZE))
PROBE_CPU_ESP_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (4 * PTR_SIZE))
PROBE_CPU_EBP_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (5 * PTR_SIZE))
PROBE_CPU_ESI_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (6 * PTR_SIZE))
PROBE_CPU_EDI_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (7 * PTR_SIZE))
PROBE_CPU_R8_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (8 * PTR_SIZE))
PROBE_CPU_R9_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (9 * PTR_SIZE))
PROBE_CPU_R10_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (10 * PTR_SIZE))
PROBE_CPU_R11_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (11 * PTR_SIZE))
PROBE_CPU_R12_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (12 * PTR_SIZE))
PROBE_CPU_R13_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (13 * PTR_SIZE))
PROBE_CPU_R14_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (14 * PTR_SIZE))
PROBE_CPU_R15_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (15 * PTR_SIZE))
PROBE_FIRST_SPR_OFFSET EQU (PROBE_FIRST_GPR_OFFSET + (16 * PTR_SIZE))
PROBE_CPU_EIP_OFFSET EQU (PROBE_FIRST_SPR_OFFSET + (0 * PTR_SIZE))
PROBE_CPU_EFLAGS_OFFSET EQU (PROBE_FIRST_SPR_OFFSET + (1 * PTR_SIZE))
PROBE_FIRST_XMM_OFFSET EQU (PROBE_FIRST_SPR_OFFSET + (2 * PTR_SIZE))
XMM_SIZE EQU 8
PROBE_CPU_XMM0_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (0 * XMM_SIZE))
PROBE_CPU_XMM1_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (1 * XMM_SIZE))
PROBE_CPU_XMM2_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (2 * XMM_SIZE))
PROBE_CPU_XMM3_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (3 * XMM_SIZE))
PROBE_CPU_XMM4_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (4 * XMM_SIZE))
PROBE_CPU_XMM5_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (5 * XMM_SIZE))
PROBE_CPU_XMM6_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (6 * XMM_SIZE))
PROBE_CPU_XMM7_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (7 * XMM_SIZE))
PROBE_CPU_XMM8_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (8 * XMM_SIZE))
PROBE_CPU_XMM9_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (9 * XMM_SIZE))
PROBE_CPU_XMM10_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (10 * XMM_SIZE))
PROBE_CPU_XMM11_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (11 * XMM_SIZE))
PROBE_CPU_XMM12_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (12 * XMM_SIZE))
PROBE_CPU_XMM13_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (13 * XMM_SIZE))
PROBE_CPU_XMM14_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (14 * XMM_SIZE))
PROBE_CPU_XMM15_OFFSET EQU (PROBE_FIRST_XMM_OFFSET + (15 * XMM_SIZE))
PROBE_SIZE EQU (PROBE_CPU_XMM15_OFFSET + XMM_SIZE)
PROBE_EXECUTOR_OFFSET EQU PROBE_SIZE ; Stash the executeProbe function pointer at the end of the ProbeContext.
OUT_SIZE EQU (5 * PTR_SIZE)
ctiMasmProbeTrampoline PROC
pushfq
; MacroAssemblerX86Common::probe() has already generated code to store some values.
; Together with the rflags pushed above, the top of stack now looks like this:
; rsp[0 * ptrSize]: rflags
; rsp[1 * ptrSize]: return address / saved rip
; rsp[2 * ptrSize]: saved rbx
; rsp[3 * ptrSize]: saved rdx
; rsp[4 * ptrSize]: saved rcx
; rsp[5 * ptrSize]: saved rax
;
; Incoming registers contain:
; rcx: Probe::executeProbe
; rdx: probe function
; rbx: probe arg
; rax: scratch (was ctiMasmProbeTrampoline)
mov rax, rsp
sub rsp, PROBE_SIZE + OUT_SIZE
; The X86_64 ABI specifies that the worse case stack alignment requirement is 32 bytes.
and rsp, not 01fh
; Since sp points to the ProbeContext, we've ensured that it's protected from interrupts before we initialize it.
mov [PROBE_CPU_EBP_OFFSET + rsp], rbp
mov rbp, rsp ; Save the ProbeContext*.
mov [PROBE_EXECUTOR_OFFSET + rbp], rcx
mov [PROBE_PROBE_FUNCTION_OFFSET + rbp], rdx
mov [PROBE_ARG_OFFSET + rbp], rbx
mov [PROBE_CPU_ESI_OFFSET + rbp], rsi
mov [PROBE_CPU_EDI_OFFSET + rbp], rdi
mov rcx, [0 * PTR_SIZE + rax]
mov [PROBE_CPU_EFLAGS_OFFSET + rbp], rcx
mov rcx, [1 * PTR_SIZE + rax]
mov [PROBE_CPU_EIP_OFFSET + rbp], rcx
mov rcx, [2 * PTR_SIZE + rax]
mov [PROBE_CPU_EBX_OFFSET + rbp], rcx
mov rcx, [3 * PTR_SIZE + rax]
mov [PROBE_CPU_EDX_OFFSET + rbp], rcx
mov rcx, [4 * PTR_SIZE + rax]
mov [PROBE_CPU_ECX_OFFSET + rbp], rcx
mov rcx, [5 * PTR_SIZE + rax]
mov [PROBE_CPU_EAX_OFFSET + rbp], rcx
mov rcx, rax
add rcx, 6 * PTR_SIZE
mov [PROBE_CPU_ESP_OFFSET + rbp], rcx
mov [PROBE_CPU_R8_OFFSET + rbp], r8
mov [PROBE_CPU_R9_OFFSET + rbp], r9
mov [PROBE_CPU_R10_OFFSET + rbp], r10
mov [PROBE_CPU_R11_OFFSET + rbp], r11
mov [PROBE_CPU_R12_OFFSET + rbp], r12
mov [PROBE_CPU_R13_OFFSET + rbp], r13
mov [PROBE_CPU_R14_OFFSET + rbp], r14
mov [PROBE_CPU_R15_OFFSET + rbp], r15
movq qword ptr [PROBE_CPU_XMM0_OFFSET + rbp], xmm0
movq qword ptr [PROBE_CPU_XMM1_OFFSET + rbp], xmm1
movq qword ptr [PROBE_CPU_XMM2_OFFSET + rbp], xmm2
movq qword ptr [PROBE_CPU_XMM3_OFFSET + rbp], xmm3
movq qword ptr [PROBE_CPU_XMM4_OFFSET + rbp], xmm4
movq qword ptr [PROBE_CPU_XMM5_OFFSET + rbp], xmm5
movq qword ptr [PROBE_CPU_XMM6_OFFSET + rbp], xmm6
movq qword ptr [PROBE_CPU_XMM7_OFFSET + rbp], xmm7
movq qword ptr [PROBE_CPU_XMM8_OFFSET + rbp], xmm8
movq qword ptr [PROBE_CPU_XMM9_OFFSET + rbp], xmm9
movq qword ptr [PROBE_CPU_XMM10_OFFSET + rbp], xmm10
movq qword ptr [PROBE_CPU_XMM11_OFFSET + rbp], xmm11
movq qword ptr [PROBE_CPU_XMM12_OFFSET + rbp], xmm12
movq qword ptr [PROBE_CPU_XMM13_OFFSET + rbp], xmm13
movq qword ptr [PROBE_CPU_XMM14_OFFSET + rbp], xmm14
movq qword ptr [PROBE_CPU_XMM15_OFFSET + rbp], xmm15
mov rcx, rbp ; the Probe::State* arg.
sub rsp, 32 ; shadow space
call qword ptr[PROBE_EXECUTOR_OFFSET + rbp]
add rsp, 32
; Make sure the ProbeContext is entirely below the result stack pointer so
; that register values are still preserved when we call the initializeStack
; function.
mov rcx, PROBE_SIZE + OUT_SIZE
mov rax, rbp
mov rdx, [PROBE_CPU_ESP_OFFSET + rbp]
add rax, rcx
cmp rdx, rax
jge ctiMasmProbeTrampolineProbeContextIsSafe
; Allocate a safe place on the stack below the result stack pointer to stash the ProbeContext.
sub rdx, rcx
and rdx, not 01fh ; Keep the stack pointer 32 bytes aligned.
xor rax, rax
mov rsp, rdx
mov rcx, PROBE_SIZE
; Copy the ProbeContext to the safe place.
ctiMasmProbeTrampolineCopyLoop:
mov rdx, [rbp + rax]
mov [rsp + rax], rdx
add rax, PTR_SIZE
cmp rcx, rax
jg ctiMasmProbeTrampolineCopyLoop
mov rbp, rsp
; Call initializeStackFunction if present.
ctiMasmProbeTrampolineProbeContextIsSafe:
xor rcx, rcx
add rcx, [PROBE_INIT_STACK_FUNCTION_OFFSET + rbp]
je ctiMasmProbeTrampolineRestoreRegisters
mov rdx, rcx
mov rcx, rbp ; the Probe::State* arg.
sub rsp, 32 ; shadow space
call rdx
add rsp, 32
ctiMasmProbeTrampolineRestoreRegisters:
; To enable probes to modify register state, we copy all registers
; out of the ProbeContext before returning.
mov rdx, [PROBE_CPU_EDX_OFFSET + rbp]
mov rbx, [PROBE_CPU_EBX_OFFSET + rbp]
mov rsi, [PROBE_CPU_ESI_OFFSET + rbp]
mov rdi, [PROBE_CPU_EDI_OFFSET + rbp]
mov r8, [PROBE_CPU_R8_OFFSET + rbp]
mov r9, [PROBE_CPU_R9_OFFSET + rbp]
mov r10, [PROBE_CPU_R10_OFFSET + rbp]
mov r11, [PROBE_CPU_R11_OFFSET + rbp]
mov r12, [PROBE_CPU_R12_OFFSET + rbp]
mov r13, [PROBE_CPU_R13_OFFSET + rbp]
mov r14, [PROBE_CPU_R14_OFFSET + rbp]
mov r15, [PROBE_CPU_R15_OFFSET + rbp]
movq xmm0, qword ptr[PROBE_CPU_XMM0_OFFSET + rbp]
movq xmm1, qword ptr[PROBE_CPU_XMM1_OFFSET + rbp]
movq xmm2, qword ptr[PROBE_CPU_XMM2_OFFSET + rbp]
movq xmm3, qword ptr[PROBE_CPU_XMM3_OFFSET + rbp]
movq xmm4, qword ptr[PROBE_CPU_XMM4_OFFSET + rbp]
movq xmm5, qword ptr[PROBE_CPU_XMM5_OFFSET + rbp]
movq xmm6, qword ptr[PROBE_CPU_XMM6_OFFSET + rbp]
movq xmm7, qword ptr[PROBE_CPU_XMM7_OFFSET + rbp]
movq xmm8, qword ptr[PROBE_CPU_XMM8_OFFSET + rbp]
movq xmm9, qword ptr[PROBE_CPU_XMM9_OFFSET + rbp]
movq xmm10, qword ptr[PROBE_CPU_XMM10_OFFSET + rbp]
movq xmm11, qword ptr[PROBE_CPU_XMM11_OFFSET + rbp]
movq xmm12, qword ptr[PROBE_CPU_XMM12_OFFSET + rbp]
movq xmm13, qword ptr[PROBE_CPU_XMM13_OFFSET + rbp]
movq xmm14, qword ptr[PROBE_CPU_XMM14_OFFSET + rbp]
movq xmm15, qword ptr[PROBE_CPU_XMM15_OFFSET + rbp]
; There are 6 more registers left to restore:
; rax, rcx, rbp, rsp, rip, and rflags.
; The restoration process at ctiMasmProbeTrampolineEnd below works by popping
; 5 words off the stack into rflags, rax, rcx, rbp, and rip. These 5 words need
; to be pushed on top of the final esp value so that just by popping the 5 words,
; we'll get the esp that the probe wants to set. Let's call this area (for storing
; these 5 words) the restore area.
mov rcx, [PROBE_CPU_ESP_OFFSET + rbp]
sub rcx, 5 * PTR_SIZE
; rcx now points to the restore area.
; Copy remaining restore values from the ProbeContext to the restore area.
; Note: We already ensured above that the ProbeContext is in a safe location before
; calling the initializeStackFunction. The initializeStackFunction is not allowed to
; change the stack pointer again.
mov rax, [PROBE_CPU_EFLAGS_OFFSET + rbp]
mov [0 * PTR_SIZE + rcx], rax
mov rax, [PROBE_CPU_EAX_OFFSET + rbp]
mov [1 * PTR_SIZE + rcx], rax
mov rax, [PROBE_CPU_ECX_OFFSET + rbp]
mov [2 * PTR_SIZE + rcx], rax
mov rax, [PROBE_CPU_EBP_OFFSET + rbp]
mov [3 * PTR_SIZE + rcx], rax
mov rax, [PROBE_CPU_EIP_OFFSET + rbp]
mov [4 * PTR_SIZE + rcx], rax
mov rsp, rcx
; Do the remaining restoration by popping off the restore area.
popfq
pop rax
pop rcx
pop rbp
ret
ctiMasmProbeTrampoline ENDP
_TEXT ENDS
END