1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/config.h>
29 #include <com/sun/star/uno/genfunc.hxx>
30 #include <sal/log.hxx>
32 #include <typelib/typedescription.hxx>
35 #include <cppinterfaceproxy.hxx>
37 #include <vtablefactory.hxx>
40 #include <msvc/cpp2uno.hxx>
41 #include <msvc/amd64.hxx>
43 extern "C" IMAGE_DOS_HEADER
const __ImageBase
;
45 using namespace ::com::sun::star
;
47 extern "C" typelib_TypeClass
cpp_vtable_call(sal_Int64 nOffsetAndIndex
, void ** pCallStack
)
49 sal_Int32 nFunctionIndex
= (nOffsetAndIndex
& 0xFFFFFFFF);
50 sal_Int32 nVtableOffset
= ((nOffsetAndIndex
>> 32) & 0xFFFFFFFF);
51 return cpp_mediate(pCallStack
, nFunctionIndex
, nVtableOffset
, nullptr);
54 int const codeSnippetSize
= 48;
58 typedef enum { REGPARAM_INT
, REGPARAM_FLT
} RegParamKind
;
62 extern "C" char privateSnippetExecutor
;
64 // This function generates the code that acts as a proxy for the UNO function to be called.
65 // The generated code does the following:
66 // - Spills register parameters on stack
67 // - Loads functionIndex and vtableOffset into scratch registers
68 // - Jumps to privateSnippetExecutor
70 static unsigned char * codeSnippet(
72 RegParamKind param_kind
[4],
73 sal_Int32 nFunctionIndex
,
74 sal_Int32 nVtableOffset
)
76 sal_uInt64 nOffsetAndIndex
= ( static_cast<sal_uInt64
>(nVtableOffset
) << 32 ) | static_cast<sal_uInt64
>(nFunctionIndex
);
77 unsigned char *p
= code
;
80 if (param_kind
[0] == REGPARAM_INT
)
82 // mov qword ptr 8[rsp], rcx
83 *p
++ = 0x48; *p
++ = 0x89; *p
++ = 0x4C; *p
++ = 0x24; *p
++ = 0x08;
87 // movsd qword ptr 8[rsp], xmm0
88 *p
++ = 0xF2; *p
++ = 0x0F; *p
++ = 0x11; *p
++ = 0x44; *p
++ = 0x24; *p
++ = 0x08;
90 if ( param_kind
[1] == REGPARAM_INT
)
92 // mov qword ptr 16[rsp], rdx
93 *p
++ = 0x48; *p
++ = 0x89; *p
++ = 0x54; *p
++ = 0x24; *p
++ = 0x10;
97 // movsd qword ptr 16[rsp], xmm1
98 *p
++ = 0xF2; *p
++ = 0x0F; *p
++ = 0x11; *p
++ = 0x4C; *p
++ = 0x24; *p
++ = 0x10;
100 if ( param_kind
[2] == REGPARAM_INT
)
102 // mov qword ptr 24[rsp], r8
103 *p
++ = 0x4C; *p
++ = 0x89; *p
++ = 0x44; *p
++ = 0x24; *p
++ = 0x18;
107 // movsd qword ptr 24[rsp], xmm2
108 *p
++ = 0xF2; *p
++ = 0x0F; *p
++ = 0x11; *p
++ = 0x54; *p
++ = 0x24; *p
++ = 0x18;
110 if ( param_kind
[3] == REGPARAM_INT
)
112 // mov qword ptr 32[rsp], r9
113 *p
++ = 0x4C;*p
++ = 0x89; *p
++ = 0x4C; *p
++ = 0x24; *p
++ = 0x20;
117 // movsd qword ptr 32[rsp], xmm3
118 *p
++ = 0xF2; *p
++ = 0x0F; *p
++ = 0x11; *p
++ = 0x5C; *p
++ = 0x24; *p
++ = 0x20;
121 // mov rcx, nOffsetAndIndex
122 *p
++ = 0x48; *p
++ = 0xB9;
123 *reinterpret_cast<sal_uInt64
*>(p
) = nOffsetAndIndex
; p
+= 8;
125 // mov r11, privateSnippetExecutor
126 *p
++ = 0x49; *p
++ = 0xBB;
127 *reinterpret_cast<void **>(p
) = &privateSnippetExecutor
; p
+= 8;
130 *p
++ = 0x41; *p
++ = 0xFF; *p
++ = 0xE3;
132 assert(p
< code
+ codeSnippetSize
);
134 return code
+ codeSnippetSize
;
137 struct bridges::cpp_uno::shared::VtableFactory::Slot
{ void * fn
; };
139 bridges::cpp_uno::shared::VtableFactory::Slot
*
140 bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(
143 return static_cast< Slot
* >(block
) + 1;
146 std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(
149 return (slotCount
+ 1) * sizeof (Slot
) + slotCount
* codeSnippetSize
;
152 static sal_uInt32
imageRelative(void const * p
) {
154 reinterpret_cast<sal_uIntPtr
>(p
) >= reinterpret_cast<sal_uIntPtr
>(&__ImageBase
)
155 && reinterpret_cast<sal_uIntPtr
>(p
) - reinterpret_cast<sal_uIntPtr
>(&__ImageBase
)
156 <= std::numeric_limits
<sal_uInt32
>::max());
157 return reinterpret_cast<sal_uIntPtr
>(p
) - reinterpret_cast<sal_uIntPtr
>(&__ImageBase
);
162 // Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast
163 // on such proxy objects not crash:
166 // The following vtable RTTI data is based on how the code at
167 // <https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/MicrosoftCXXABI.cpp> computes
168 // such data, and on how <https://devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483>
169 // "Accessing the current module’s HINSTANCE from a static library" obtians __ImageBase:
171 struct RttiClassHierarchyDescriptor
;
173 #pragma warning (push)
174 #pragma warning (disable: 4324) // "structure was padded due to alignment specifier"
176 struct alignas(16) RttiBaseClassDescriptor
{
177 sal_uInt32 n0
= imageRelative(&typeid(ProxyRtti
));
180 sal_uInt32 n3
= 0xFFFFFFFF;
182 sal_uInt32 n5
= 0x40;
184 RttiBaseClassDescriptor(RttiClassHierarchyDescriptor
const * chd
): n6(imageRelative(chd
)) {}
187 struct alignas(4) RttiBaseClassArray
{
190 RttiBaseClassArray(RttiBaseClassDescriptor
const * bcd
): n0(imageRelative(bcd
)) {}
193 struct alignas(8) RttiClassHierarchyDescriptor
{
198 RttiClassHierarchyDescriptor(RttiBaseClassArray
const * bca
): n3(imageRelative(bca
)) {}
201 struct alignas(16) RttiCompleteObjectLocator
{
205 sal_uInt32 n3
= imageRelative(&typeid(ProxyRtti
));
207 sal_uInt32 n5
= imageRelative(this);
208 RttiCompleteObjectLocator(RttiClassHierarchyDescriptor
const * chd
): n4(imageRelative(chd
)) {}
212 RttiBaseClassDescriptor bcd
;
213 RttiBaseClassArray bca
;
214 RttiClassHierarchyDescriptor chd
;
215 RttiCompleteObjectLocator col
;
216 Rtti(): bcd(&chd
), bca(&bcd
), chd(&bca
), col(&chd
) {}
219 #pragma warning (pop)
223 bridges::cpp_uno::shared::VtableFactory::Slot
*
224 bridges::cpp_uno::shared::VtableFactory::initializeBlock(
227 sal_Int32
, typelib_InterfaceTypeDescription
*)
231 Slot
* slots
= mapBlockToVtable(block
);
232 slots
[-1].fn
= &rtti
.col
;
233 return slots
+ slotCount
;
236 unsigned char * bridges::cpp_uno::shared::VtableFactory::addLocalFunctions(
238 unsigned char * code
,
239 typelib_InterfaceTypeDescription
const * type
,
240 sal_Int32 nFunctionOffset
,
241 sal_Int32 functionCount
,
242 sal_Int32 nVtableOffset
)
244 (*slots
) -= functionCount
;
247 for (int member
= 0; member
< type
->nMembers
; ++member
) {
248 typelib_TypeDescription
* pTD
= nullptr;
250 TYPELIB_DANGER_GET( &pTD
, type
->ppMembers
[ member
] );
253 RegParamKind param_kind
[4];
256 for (int i
= 0; i
< 4; ++i
)
257 param_kind
[i
] = REGPARAM_INT
;
262 if ( pTD
->eTypeClass
== typelib_TypeClass_INTERFACE_ATTRIBUTE
)
264 typelib_InterfaceAttributeTypeDescription
* pIfaceAttrTD
=
265 reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>( pTD
);
270 code
= codeSnippet( code
, param_kind
, nFunctionOffset
++, nVtableOffset
);
271 if ( ! pIfaceAttrTD
->bReadOnly
)
273 typelib_TypeDescription
* pAttrTD
= nullptr;
274 TYPELIB_DANGER_GET( &pAttrTD
, pIfaceAttrTD
->pAttributeTypeRef
);
278 if ( pAttrTD
->eTypeClass
== typelib_TypeClass_FLOAT
||
279 pAttrTD
->eTypeClass
== typelib_TypeClass_DOUBLE
)
280 param_kind
[nr
++] = REGPARAM_FLT
;
282 TYPELIB_DANGER_RELEASE( pAttrTD
);
285 code
= codeSnippet( code
, param_kind
, nFunctionOffset
++, nVtableOffset
);
288 else if ( pTD
->eTypeClass
== typelib_TypeClass_INTERFACE_METHOD
)
290 typelib_InterfaceMethodTypeDescription
* pMethodTD
=
291 reinterpret_cast<typelib_InterfaceMethodTypeDescription
*>( pTD
);
293 typelib_TypeDescription
* pReturnTD
= nullptr;
294 TYPELIB_DANGER_GET( &pReturnTD
, pMethodTD
->pReturnTypeRef
);
297 if ( !bridges::cpp_uno::shared::isSimpleType( pReturnTD
) )
303 for (int param
= 0; nr
< 4 && param
< pMethodTD
->nParams
; ++param
, ++nr
)
305 typelib_TypeDescription
* pParamTD
= nullptr;
307 TYPELIB_DANGER_GET( &pParamTD
, pMethodTD
->pParams
[param
].pTypeRef
);
310 if ( pParamTD
->eTypeClass
== typelib_TypeClass_FLOAT
||
311 pParamTD
->eTypeClass
== typelib_TypeClass_DOUBLE
)
312 param_kind
[nr
] = REGPARAM_FLT
;
314 TYPELIB_DANGER_RELEASE( pParamTD
);
317 code
= codeSnippet( code
, param_kind
, nFunctionOffset
++, nVtableOffset
);
319 TYPELIB_DANGER_RELEASE( pReturnTD
);
324 TYPELIB_DANGER_RELEASE( pTD
);
329 void bridges::cpp_uno::shared::VtableFactory::flushCode(
330 unsigned char const *,
331 unsigned char const *)
335 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */