1; 2; Licensed to the Apache Software Foundation (ASF) under one 3; or more contributor license agreements. See the NOTICE file 4; distributed with this work for additional information 5; regarding copyright ownership. The ASF licenses this file 6; to you under the Apache License, Version 2.0 (the 7; "License"); you may not use this file except in compliance 8; with the License. You may obtain a copy of the License at 9; 10; http://www.apache.org/licenses/LICENSE-2.0 11; 12; Unless required by applicable law or agreed to in writing, 13; software distributed under the License is distributed on an 14; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15; KIND, either express or implied. See the License for the 16; specific language governing permissions and limitations 17; under the License. 18; 19 20 21typelib_TypeClass_VOID equ 0 22typelib_TypeClass_CHAR equ 1 23typelib_TypeClass_BOOLEAN equ 2 24typelib_TypeClass_BYTE equ 3 25typelib_TypeClass_SHORT equ 4 26typelib_TypeClass_UNSIGNED_SHORT equ 5 27typelib_TypeClass_LONG equ 6 28typelib_TypeClass_UNSIGNED_LONG equ 7 29typelib_TypeClass_HYPER equ 8 30typelib_TypeClass_UNSIGNED_HYPER equ 9 31typelib_TypeClass_FLOAT equ 10 32typelib_TypeClass_DOUBLE equ 11 33typelib_TypeClass_ENUM equ 15 34 35EXTERN cpp_vtable_call: PROC 36 37.CODE 38 39; 40; | ... | 41; +----------------------------+ 42; | argument 4 | 43; rbp+48 rsp+40 +----------------------------+ ------- 44; | argument 3, r9/xmm3 home | ^ shadow 45; rbp+40 rsp+32 +----------------------------+ | space, 46; | argument 2, r8/xmm2 home | | guaranteed to be present but uninitialized, 47; rbp+32 rsp+24 +----------------------------+ | we have to copy 48; | argument 1, rdx/xmm1 home | | the first 4 parameters there from the registers, 49; rbp+24 rsp+16 +----------------------------+ | to form the continuous array of arguments. 50; | argument 0, rcx/xmm0 home | v 51; rbp+16 rsp+08 +----------------------------+ ------- 52; | return address | 53; rbp+08 rsp--> +----------------------------+ 54; | old rbp | 55; rbp---------> +----------------------------+ 56; | pRegisterReturn memory | 57; rbp-08 -----> +----------------------------+ 58; | | 59; rbp-16 -----> +----------------------------+ ------- 60; | | ^ 61; rbp-24 -----> +----------------------------+ | shadow space 62; | | | for cpp_vtable_call 63; rbp-32 -----> +----------------------------+ | 64; | | | 65; rbp-40 -----> +----------------------------+ | 66; | | v 67; rbp-48 -----> +----------------------------+ ------- 68; 69; rax = functionIndex 70; r10 = vtableOffset 71; r11 = &privateSnippetExecutor 72; 73 74privateSnippetExecutor PROC FRAME 75 76 push rbp 77 mov rbp, rsp 78 sub rsp, 48 79 .ALLOCSTACK(48) 80 .ENDPROLOG 81 82 ; 4th param: sal_uInt64 *pRegisterReturn 83 lea r9, -8[rbp] 84 85 ; 3rd param: sal_Int32 nVtableOffset 86 mov r8, r10 87 88 ; 2nd param: sal_Int32 nFunctionIndex 89 mov rdx, rax 90 91 ; 1st param: void ** pCallStack 92 lea rcx, 8[rbp] 93 94 call cpp_vtable_call 95 96 ; Integers would return in RAX and floats in XMM0, but both are free for us to clobber, 97 ; and the caller knows where to look: 98 mov rax, -8[rbp] 99 movsd xmm0, qword ptr -8[rbp] 100 101 leave 102 ret 103 104privateSnippetExecutor ENDP 105 106 107; 108; | ... | 109; rbp+64 -----> +---------------------------------------------+ 110; | sal_uInt32 nStack | 111; rbp+56 -----> +---------------------------------------------+ 112; | sal_uInt64 *pStack | 113; rbp+48 -----> +---------------------------------------------+ ------- 114; | typelib_TypeClass eReturnTypeClass, r9 home | ^ shadow 115; rbp+40 -----> +---------------------------------------------+ | space, 116; | void *pRegisterReturn, r8 home | | guaranteed to be present but uninitialized, 117; rbp+32 -----> +---------------------------------------------+ | we have to copy 118; | sal_Int32 nVtableIndex, rdx home | | the first 4 parameters there from the registers, 119; rbp+24 -----> +---------------------------------------------+ | to form the continuous array of arguments. 120; | void* pAdjustedThisPtr, rcx home | v 121; rbp+16 -----> +---------------------------------------------+ ------- 122; | return address | 123; rbp+08 -----> +---------------------------------------------+ 124; | old rbp | 125; rbp --------> +---------------------------------------------+ <---- 16 byte boundary 126; | (possible 16 byte alignment placeholder) | 127; rbp-08 -----> +---------------------------------------------+ 128; | (stack for virtual method) | 129; | ... | 130; | (shadow space for virtual method) | 131; rsp --------> +---------------------------------------------+ <---- 16 byte boundary 132 133callVirtualMethod PROC FRAME 134 135 push rbp 136 mov rbp, rsp 137 .ENDPROLOG 138 139 ; Save our register arguments to the shadow space: 140 mov 16[rbp], rcx 141 mov 24[rbp], rdx 142 mov 32[rbp], r8 143 mov 40[rbp], r9 144 145 ; We must maintain the stack aligned to a 16 byte boundary: 146 mov eax, 56[rbp] 147 cmp rax, 0 148 je stackIsEmpty 149 mov r11, rax 150 test rax,1 151 jz stackSizeEven 152 sub rsp, 8 153stackSizeEven: 154 mov r10, 48[rbp] 155 shl rax, 3 ; nStack is in units of sal_uInt64, and sizeof(sal_uInt64) == 8 156 add rax, r10 157 158copyStack: 159 sub rax, 8 160 push [rax] 161 dec r11 162 jne copyStack 163 164 ; First 4 args are passed in registers. Floating point args needs to be 165 ; in floating point registers, but those are free for us to clobber 166 ; anyway, and the callee knows where to look, so put each arg in both 167 ; its general purpose and its floating point register: 168 mov rcx, [rsp] 169 movsd xmm0, qword ptr [rsp] 170 mov rdx, 8[rsp] 171 movsd xmm1, qword ptr 8[rsp] 172 mov r8, 16[rsp] 173 movsd xmm2, qword ptr 16[rsp] 174 mov r9, 24[rsp] 175 movsd xmm3, qword ptr 24[rsp] 176 jmp callMethod 177 178stackIsEmpty: 179 sub rsp, 32 ; we still need shadow space 180 181callMethod: 182 ; Find the method pointer 183 mov rax, 16[rbp] 184 mov r10, [rax] ; pointer to vtable 185 mov r11d, 24[rbp] 186 shl r11, 3 ; sizeof(void*) == 8 187 add r10, r11 188 call qword ptr [r10] 189 190 mov r10d, 40[rbp] 191 cmp r10, typelib_TypeClass_VOID 192 je cleanup 193 cmp r10, typelib_TypeClass_LONG 194 je Lint32 195 cmp r10, typelib_TypeClass_UNSIGNED_LONG 196 je Lint32 197 cmp r10, typelib_TypeClass_ENUM 198 je Lint32 199 cmp r10, typelib_TypeClass_BOOLEAN 200 je Lint8 201 cmp r10, typelib_TypeClass_BYTE 202 je Lint8 203 cmp r10, typelib_TypeClass_CHAR 204 je Lint16 205 cmp r10, typelib_TypeClass_SHORT 206 je Lint16 207 cmp r10, typelib_TypeClass_UNSIGNED_SHORT 208 je Lint16 209 cmp r10, typelib_TypeClass_FLOAT 210 je Lfloat 211 cmp r10, typelib_TypeClass_DOUBLE 212 je Lfloat 213 cmp r10, typelib_TypeClass_HYPER 214 je Lint64 215 cmp r10, typelib_TypeClass_UNSIGNED_HYPER 216 je Lint64 217 218 ; https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017 219 ; "The same pointer must be returned by the callee in RAX." 220 jmp Lint64 221 222Lint64: 223 mov 32[rbp], rax 224 jmp cleanup 225 226Lint32: 227 mov 32[rbp], eax 228 jmp cleanup 229 230Lint16: 231 mov 32[rbp], ax 232 jmp cleanup 233 234Lint8: 235 mov 32[rbp], al 236 jmp cleanup 237 238Lfloat: 239 movsd qword ptr 32[rbp], xmm0 240 jmp cleanup 241 242cleanup: 243 leave 244 ret 245 246callVirtualMethod ENDP 247 248 249END 250