; ; Licensed to the Apache Software Foundation (ASF) under one ; or more contributor license agreements. See the NOTICE file ; distributed with this work for additional information ; regarding copyright ownership. The ASF licenses this file ; to you under the Apache License, Version 2.0 (the ; "License"); you may not use this file except in compliance ; with the License. You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, ; software distributed under the License is distributed on an ; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ; KIND, either express or implied. See the License for the ; specific language governing permissions and limitations ; under the License. ; typelib_TypeClass_VOID equ 0 typelib_TypeClass_CHAR equ 1 typelib_TypeClass_BOOLEAN equ 2 typelib_TypeClass_BYTE equ 3 typelib_TypeClass_SHORT equ 4 typelib_TypeClass_UNSIGNED_SHORT equ 5 typelib_TypeClass_LONG equ 6 typelib_TypeClass_UNSIGNED_LONG equ 7 typelib_TypeClass_HYPER equ 8 typelib_TypeClass_UNSIGNED_HYPER equ 9 typelib_TypeClass_FLOAT equ 10 typelib_TypeClass_DOUBLE equ 11 typelib_TypeClass_ENUM equ 15 EXTERN cpp_vtable_call: PROC .CODE ; ; | ... | ; +----------------------------+ ; | argument 4 | ; rbp+48 rsp+40 +----------------------------+ ------- ; | argument 3, r9/xmm3 home | ^ shadow ; rbp+40 rsp+32 +----------------------------+ | space, ; | argument 2, r8/xmm2 home | | guaranteed to be present but uninitialized, ; rbp+32 rsp+24 +----------------------------+ | we have to copy ; | argument 1, rdx/xmm1 home | | the first 4 parameters there from the registers, ; rbp+24 rsp+16 +----------------------------+ | to form the continuous array of arguments. ; | argument 0, rcx/xmm0 home | v ; rbp+16 rsp+08 +----------------------------+ ------- ; | return address | ; rbp+08 rsp--> +----------------------------+ ; | old rbp | ; rbp---------> +----------------------------+ ; | pRegisterReturn memory | ; rbp-08 -----> +----------------------------+ ; | | ; rbp-16 -----> +----------------------------+ ------- ; | | ^ ; rbp-24 -----> +----------------------------+ | shadow space ; | | | for cpp_vtable_call ; rbp-32 -----> +----------------------------+ | ; | | | ; rbp-40 -----> +----------------------------+ | ; | | v ; rbp-48 -----> +----------------------------+ ------- ; ; rax = functionIndex ; r10 = vtableOffset ; r11 = &privateSnippetExecutor ; privateSnippetExecutor PROC FRAME push rbp mov rbp, rsp sub rsp, 48 .ALLOCSTACK(48) .ENDPROLOG ; 4th param: sal_uInt64 *pRegisterReturn lea r9, -8[rbp] ; 3rd param: sal_Int32 nVtableOffset mov r8, r10 ; 2nd param: sal_Int32 nFunctionIndex mov rdx, rax ; 1st param: void ** pCallStack lea rcx, 8[rbp] call cpp_vtable_call ; Integers would return in RAX and floats in XMM0, but both are free for us to clobber, ; and the caller knows where to look: mov rax, -8[rbp] movsd xmm0, qword ptr -8[rbp] leave ret privateSnippetExecutor ENDP ; ; | ... | ; rbp+64 -----> +---------------------------------------------+ ; | sal_uInt32 nStack | ; rbp+56 -----> +---------------------------------------------+ ; | sal_uInt64 *pStack | ; rbp+48 -----> +---------------------------------------------+ ------- ; | typelib_TypeClass eReturnTypeClass, r9 home | ^ shadow ; rbp+40 -----> +---------------------------------------------+ | space, ; | void *pRegisterReturn, r8 home | | guaranteed to be present but uninitialized, ; rbp+32 -----> +---------------------------------------------+ | we have to copy ; | sal_Int32 nVtableIndex, rdx home | | the first 4 parameters there from the registers, ; rbp+24 -----> +---------------------------------------------+ | to form the continuous array of arguments. ; | void* pAdjustedThisPtr, rcx home | v ; rbp+16 -----> +---------------------------------------------+ ------- ; | return address | ; rbp+08 -----> +---------------------------------------------+ ; | old rbp | ; rbp --------> +---------------------------------------------+ <---- 16 byte boundary ; | (possible 16 byte alignment placeholder) | ; rbp-08 -----> +---------------------------------------------+ ; | (stack for virtual method) | ; | ... | ; | (shadow space for virtual method) | ; rsp --------> +---------------------------------------------+ <---- 16 byte boundary callVirtualMethod PROC FRAME push rbp mov rbp, rsp .ENDPROLOG ; Save our register arguments to the shadow space: mov 16[rbp], rcx mov 24[rbp], rdx mov 32[rbp], r8 mov 40[rbp], r9 ; We must maintain the stack aligned to a 16 byte boundary: mov eax, 56[rbp] cmp rax, 0 je stackIsEmpty mov r11, rax test rax,1 jz stackSizeEven sub rsp, 8 stackSizeEven: mov r10, 48[rbp] shl rax, 3 ; nStack is in units of sal_uInt64, and sizeof(sal_uInt64) == 8 add rax, r10 copyStack: sub rax, 8 push [rax] dec r11 jne copyStack ; First 4 args are passed in registers. Floating point args needs to be ; in floating point registers, but those are free for us to clobber ; anyway, and the callee knows where to look, so put each arg in both ; its general purpose and its floating point register: mov rcx, [rsp] movsd xmm0, qword ptr [rsp] mov rdx, 8[rsp] movsd xmm1, qword ptr 8[rsp] mov r8, 16[rsp] movsd xmm2, qword ptr 16[rsp] mov r9, 24[rsp] movsd xmm3, qword ptr 24[rsp] jmp callMethod stackIsEmpty: sub rsp, 32 ; we still need shadow space callMethod: ; Find the method pointer mov rax, 16[rbp] mov r10, [rax] ; pointer to vtable mov r11d, 24[rbp] shl r11, 3 ; sizeof(void*) == 8 add r10, r11 call qword ptr [r10] mov r10d, 40[rbp] cmp r10, typelib_TypeClass_VOID je cleanup cmp r10, typelib_TypeClass_LONG je Lint32 cmp r10, typelib_TypeClass_UNSIGNED_LONG je Lint32 cmp r10, typelib_TypeClass_ENUM je Lint32 cmp r10, typelib_TypeClass_BOOLEAN je Lint8 cmp r10, typelib_TypeClass_BYTE je Lint8 cmp r10, typelib_TypeClass_CHAR je Lint16 cmp r10, typelib_TypeClass_SHORT je Lint16 cmp r10, typelib_TypeClass_UNSIGNED_SHORT je Lint16 cmp r10, typelib_TypeClass_FLOAT je Lfloat cmp r10, typelib_TypeClass_DOUBLE je Lfloat cmp r10, typelib_TypeClass_HYPER je Lint64 cmp r10, typelib_TypeClass_UNSIGNED_HYPER je Lint64 ; https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017 ; "The same pointer must be returned by the callee in RAX." jmp Lint64 Lint64: mov 32[rbp], rax jmp cleanup Lint32: mov 32[rbp], eax jmp cleanup Lint16: mov 32[rbp], ax jmp cleanup Lint8: mov 32[rbp], al jmp cleanup Lfloat: movsd qword ptr 32[rbp], xmm0 jmp cleanup cleanup: leave ret callVirtualMethod ENDP END