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; | caller's rbp | 55; rbp---------> +----------------------------+ <------ 16 byte boundary 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 push rbp 76 .PUSHREG rbp 77 mov rbp, rsp 78 .SETFRAME rbp, 0 79 sub rsp, 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 add rsp, 48 102 pop rbp 103 ret 104 105privateSnippetExecutor ENDP 106 107 108; 109; | ... | 110; rbp+64 -----> +---------------------------------------------+ 111; | sal_uInt32 nStack | 112; rbp+56 -----> +---------------------------------------------+ 113; | sal_uInt64 *pStack | 114; rbp+48 -----> +---------------------------------------------+ ------- 115; | typelib_TypeClass eReturnTypeClass, r9 home | ^ shadow 116; rbp+40 -----> +---------------------------------------------+ | space, 117; | void *pRegisterReturn, r8 home | | guaranteed to be present but uninitialized, 118; rbp+32 -----> +---------------------------------------------+ | we have to copy 119; | sal_Int32 nVtableIndex, rdx home | | the first 4 parameters there from the registers, 120; rbp+24 -----> +---------------------------------------------+ | to form the continuous array of arguments. 121; | void* pAdjustedThisPtr, rcx home | v 122; rbp+16 -----> +---------------------------------------------+ ------- 123; | return address | 124; rbp+08 -----> +---------------------------------------------+ 125; | caller's rbp | 126; rbp --------> +---------------------------------------------+ <---- 16 byte boundary 127; | (possible 16 byte alignment placeholder) | 128; rbp-08 -----> +---------------------------------------------+ 129; | (stack for virtual method) | 130; | ... | 131; | (shadow space for virtual method) | 132; rsp --------> +---------------------------------------------+ <---- 16 byte boundary 133 134callVirtualMethod PROC FRAME 135 136 push rbp 137 .PUSHREG rbp 138 mov rbp, rsp 139 .SETFRAME rbp, 0 140 141 ; Save our register arguments to the shadow space: 142 mov 16[rbp], rcx 143 mov 24[rbp], rdx 144 mov 32[rbp], r8 145 mov 40[rbp], r9 146 147 ; nStack rounded to multiple of 2, so the stack is aligned to a 16 byte boundary: 148 mov eax, 56[rbp] 149 inc eax 150 shr eax, 1 151 shl eax, 1 152 153 ; if nStack < 4, add (4 - nStack) empty slots to the stack: 154 mov r10d, 4 155 sub r10d, eax 156 js copyStack 157 shl r10, 3 158 sub rsp, r10 159 160copyStack: 161 mov r10, rax 162 shl rax, 3 163 add rax, 48[rbp] 164copyStackLoop: 165 sub rax, 8 166 push [rax] 167 dec r10 168 jne copyStackLoop 169 170populateArgumentRegisters: 171 ; First 4 args are passed in registers. Floating point args needs to be 172 ; in floating point registers, but those are volatile anyway, 173 ; and the callee knows where to look, so put each arg in both 174 ; its general purpose and its floating point register: 175 mov rcx, [rsp] 176 movsd xmm0, qword ptr [rsp] 177 mov rdx, 8[rsp] 178 movsd xmm1, qword ptr 8[rsp] 179 mov r8, 16[rsp] 180 movsd xmm2, qword ptr 16[rsp] 181 mov r9, 24[rsp] 182 movsd xmm3, qword ptr 24[rsp] 183 184 .ENDPROLOG 185 186 187callMethod: 188 ; Find the method pointer 189 mov rax, 16[rbp] 190 mov r10, [rax] ; pointer to vtable 191 mov r11d, 24[rbp] 192 shl r11, 3 ; sizeof(void*) == 8 193 add r10, r11 194 call qword ptr [r10] 195 196 mov r10d, 40[rbp] 197 mov r11, 32[rbp] 198 cmp r10, typelib_TypeClass_VOID 199 je cleanup 200 cmp r10, typelib_TypeClass_LONG 201 je Lint32 202 cmp r10, typelib_TypeClass_UNSIGNED_LONG 203 je Lint32 204 cmp r10, typelib_TypeClass_ENUM 205 je Lint32 206 cmp r10, typelib_TypeClass_BOOLEAN 207 je Lint8 208 cmp r10, typelib_TypeClass_BYTE 209 je Lint8 210 cmp r10, typelib_TypeClass_CHAR 211 je Lint16 212 cmp r10, typelib_TypeClass_SHORT 213 je Lint16 214 cmp r10, typelib_TypeClass_UNSIGNED_SHORT 215 je Lint16 216 cmp r10, typelib_TypeClass_FLOAT 217 je Lfloat 218 cmp r10, typelib_TypeClass_DOUBLE 219 je Lfloat 220 cmp r10, typelib_TypeClass_HYPER 221 je Lint64 222 cmp r10, typelib_TypeClass_UNSIGNED_HYPER 223 je Lint64 224 225 ; https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017 226 ; "The same pointer must be returned by the callee in RAX." 227 jmp cleanup 228 229Lint64: 230 mov qword ptr [r11], rax 231 jmp cleanup 232 233Lint32: 234 mov dword ptr [r11], eax 235 jmp cleanup 236 237Lint16: 238 mov word ptr [r11], ax 239 jmp cleanup 240 241Lint8: 242 mov byte ptr [r11], al 243 jmp cleanup 244 245Lfloat: 246 movsd qword ptr [r11], xmm0 247 jmp cleanup 248 249cleanup: 250 lea rsp, 0[rbp] 251 pop rbp 252 ret 253 254callVirtualMethod ENDP 255 256 257END 258