LibreOffice Module bridges (master) 1
msvc_win32_intel/cpp2uno.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20
21#include <sal/config.h>
22
23#include <typeinfo>
24
25#include <malloc.h>
26
27#include <com/sun/star/uno/genfunc.hxx>
28#include <sal/log.hxx>
29#include <uno/data.h>
30#include <typelib/typedescription.hxx>
31
32#include "bridge.hxx"
33#include "cppinterfaceproxy.hxx"
34#include "types.hxx"
35#include "vtablefactory.hxx"
36
37#include <msvc/x86.hxx>
38#include <msvc/cpp2uno.hxx>
39
40using namespace ::com::sun::star;
41
42namespace
43{
44
49static __declspec(naked) void __cdecl cpp_vtable_call()
50{
51__asm
52 {
53 sub esp, 8 // space for immediate return type
54 push esp
55 push edx // vtable offset
56 push eax // function index
57 mov eax, esp
58 add eax, 20
59 push eax // original stack ptr
60
61 call cpp_mediate
62 add esp, 16
63
64 cmp eax, typelib_TypeClass_FLOAT
65 je Lfloat
66 cmp eax, typelib_TypeClass_DOUBLE
67 je Ldouble
68 cmp eax, typelib_TypeClass_HYPER
69 je Lhyper
70 cmp eax, typelib_TypeClass_UNSIGNED_HYPER
71 je Lhyper
72 // rest is eax
73 pop eax
74 add esp, 4
75 ret
76Lhyper:
77 pop eax
78 pop edx
79 ret
80Lfloat:
81 fld dword ptr [esp]
82 add esp, 8
83 ret
84Ldouble:
85 fld qword ptr [esp]
86 add esp, 8
87 ret
88 }
89}
90
91int const codeSnippetSize = 16;
92
93unsigned char * codeSnippet(
94 unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset)
95{
96 unsigned char * p = code;
97 static_assert(sizeof (sal_Int32) == 4, "boo");
98 // mov eax, functionIndex:
99 *p++ = 0xB8;
100 *reinterpret_cast< sal_Int32 * >(p) = functionIndex;
101 p += sizeof (sal_Int32);
102 // mov edx, vtableOffset:
103 *p++ = 0xBA;
104 *reinterpret_cast< sal_Int32 * >(p) = vtableOffset;
105 p += sizeof (sal_Int32);
106 // jmp rel32 cpp_vtable_call:
107 *p++ = 0xE9;
108 *reinterpret_cast< sal_Int32 * >(p)
109 = ((unsigned char *) cpp_vtable_call) - p - sizeof (sal_Int32);
110 p += sizeof (sal_Int32);
111 assert(p - code <= codeSnippetSize);
112 return code + codeSnippetSize;
113}
114
115}
116
118
121{
122 return static_cast< Slot * >(block) + 1;
123}
124
126 sal_Int32 slotCount)
127{
128 return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize;
129}
130
131namespace {
132
133// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast
134// on such proxy objects not crash:
135struct ProxyRtti {};
136
137// The following vtable RTTI data is based on how the code at
138// <https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/MicrosoftCXXABI.cpp> computes
139// such data:
140
141struct RttiClassHierarchyDescriptor;
142
143#pragma warning (push)
144#pragma warning (disable: 4324) // "structure was padded due to alignment specifier"
145
146struct alignas(16) RttiBaseClassDescriptor {
147 sal_uInt32 n0 = reinterpret_cast<sal_uInt32>(&typeid(ProxyRtti));
148 sal_uInt32 n1 = 0;
149 sal_uInt32 n2 = 0;
150 sal_uInt32 n3 = 0xFFFFFFFF;
151 sal_uInt32 n4 = 0;
152 sal_uInt32 n5 = 0x40;
153 sal_uInt32 n6;
154 RttiBaseClassDescriptor(RttiClassHierarchyDescriptor const * chd):
155 n6(reinterpret_cast<sal_uInt32>(chd)) {}
156};
157
158struct alignas(4) RttiBaseClassArray {
159 sal_uInt32 n0;
160 sal_uInt32 n1 = 0;
161 RttiBaseClassArray(RttiBaseClassDescriptor const * bcd): n0(reinterpret_cast<sal_uInt32>(bcd))
162 {}
163};
164
165struct alignas(4) RttiClassHierarchyDescriptor {
166 sal_uInt32 n0 = 0;
167 sal_uInt32 n1 = 0;
168 sal_uInt32 n2 = 1;
169 sal_uInt32 n3;
170 RttiClassHierarchyDescriptor(RttiBaseClassArray const * bca):
171 n3(reinterpret_cast<sal_uInt32>(bca)) {}
172};
173
174struct alignas(16) RttiCompleteObjectLocator {
175 sal_uInt32 n0 = 0;
176 sal_uInt32 n1 = 0;
177 sal_uInt32 n2 = 0;
178 sal_uInt32 n3 = reinterpret_cast<sal_uInt32>(&typeid(ProxyRtti));
179 sal_uInt32 n4;
180 RttiCompleteObjectLocator(RttiClassHierarchyDescriptor const * chd):
181 n4(reinterpret_cast<sal_uInt32>(chd)) {}
182};
183
184struct Rtti {
185 RttiBaseClassDescriptor bcd;
186 RttiBaseClassArray bca;
187 RttiClassHierarchyDescriptor chd;
188 RttiCompleteObjectLocator col;
189 Rtti(): bcd(&chd), bca(&bcd), chd(&bca), col(&chd) {}
190};
191
192#pragma warning (pop)
193
194}
195
198 void * block, sal_Int32 slotCount, sal_Int32,
199 typelib_InterfaceTypeDescription *)
200{
201 static Rtti rtti;
202
203 Slot * slots = mapBlockToVtable(block);
204 slots[-1].fn = &rtti.col;
205 return slots + slotCount;
206}
207
209 Slot ** slots, unsigned char * code,
210 typelib_InterfaceTypeDescription const *, sal_Int32 functionOffset,
211 sal_Int32 functionCount, sal_Int32 vtableOffset)
212{
213 (*slots) -= functionCount;
214 Slot * s = *slots;
215 for (sal_Int32 i = 0; i < functionCount; ++i) {
216 (s++)->fn = code;
217 code = codeSnippet(code, functionOffset++, vtableOffset);
218 }
219 return code;
220}
221
223 unsigned char const *,
224 unsigned char const *)
225{
226}
227
228/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static Slot * mapBlockToVtable(void *block)
Given a pointer to a block, turn it into a vtable pointer.
static void flushCode(unsigned char const *begin, unsigned char const *end)
Flush all the generated code snippets of a vtable, on platforms that require it.
static unsigned char * addLocalFunctions(Slot **slots, unsigned char *code, sal_PtrDiff writetoexecdiff, typelib_InterfaceTypeDescription const *type, sal_Int32 functionOffset, sal_Int32 functionCount, sal_Int32 vtableOffset)
Fill the vtable slots corresponding to all local (i.e., not inherited) functions of a given interface...
static Slot * initializeBlock(void *block, sal_Int32 slotCount, sal_Int32 vtableNumber, typelib_InterfaceTypeDescription *type)
Initialize a raw vtable block.
static std::size_t getBlockSize(sal_Int32 slotCount)
Calculate the size of a raw vtable block.
void cpp_vtable_call(sal_Int32 func, sal_Int32 offset, void **pStack)
is called on incoming vtable calls (called by asm snippets)
const int codeSnippetSize
static unsigned char * codeSnippet(unsigned char *code, sal_Int32 nFunctionIndex, sal_Int32 nVtableOffset, bool bHasHiddenParam)
void * p
typelib_TypeClass __cdecl cpp_mediate(void **pCallStack, const sal_Int32 nFunctionIndex, const sal_Int32 nVtableOffset, sal_Int64 *const pRegisterReturn)
RttiClassHierarchyDescriptor chd
sal_uInt32 n0
sal_uInt32 n4
sal_uInt32 n2
sal_uInt32 n5
RttiCompleteObjectLocator col
RttiBaseClassDescriptor bcd
RttiBaseClassArray bca
sal_uInt32 n6
sal_uInt32 n3
sal_uInt32 n1
static __declspec(naked) void copyConstruct()
int i
sal_Unicode code