diff options
-rw-r--r-- | bridges/source/cpp_uno/msvc_win32_x86-64/call.asm (renamed from bridges/source/cpp_uno/msvc_win32_x86-64/codeSnippet.asm) | 124 | ||||
-rw-r--r-- | bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx | 135 | ||||
-rw-r--r-- | bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk | 2 | ||||
-rw-r--r-- | bridges/source/cpp_uno/shared/vtablefactory.cxx | 24 |
4 files changed, 89 insertions, 196 deletions
diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/codeSnippet.asm b/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm index 8d76b2f8a521..ae514fd065e2 100644 --- a/bridges/source/cpp_uno/msvc_win32_x86-64/codeSnippet.asm +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/call.asm @@ -29,15 +29,18 @@ ;; in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable ;; instead of those above. -;; This is the template source code for the trampoline generated by -;; codeSnippet() in cpp2uno.cxx. codeSnippet() copies the code from -;; this function, modifying it as necessary in a few places. The -;; generated trampoline calls cpp_vtable_call() which then calls the -;; actual UNO function. +;; This is the function jumped to from the trampoline generated by +;; codeSnippet() in cpp2uno.cxx. Here we call cpp_vtable_call() which +;; then calls the actual UNO function. -;; We keep this as a separate .asm file here so that it is easy to -;; modify, and we don't need to laborously enter machine code into -;; codeSnippet(). +;; The code snippet generated is called from "normal" C++ code which +;; has no idea that it is calling dynamically generated code. + +;; The generated short code snippet is not covered by any function +;; table and unwind info, but that doesn't matter, as the instructions +;; in it are not really going to cause any exception. Once it jumps +;; here it is covered by a function table, and the calls further down +;; through cpp_vtable_call() can be unwound cleanly. ;; This is in a separate file for x86-64 as MSVC doesn't have in-line ;; assembly for x64. @@ -73,9 +76,6 @@ ;; information, for instance: ;; http://www.nynaeve.net/?p=11 -;; The code snippet generated is called from "normal" C++ code which -;; has no idea that it is calling dynamically generated code. - typelib_TypeClass_FLOAT equ 10 typelib_TypeClass_DOUBLE equ 11 @@ -83,28 +83,7 @@ extern cpp_vtable_call: proc .code -;; Single instruction templates. For each register paramter, which can -;; be either in an integer or floating-point register, either of two -;; instruction sequences are used, either: -;; mov qword ptr offset[rsp], reg -;; nop -;; or: -;; movsd qwort ptr offset[rsp], xmmreg -;; -;; The nop in the integer case is so that both are of equal length - -fp_spill_templates: -public fp_spill_templates - movsd qword ptr (40+8)[rsp], xmm0 - movsd qword ptr (40+16)[rsp], xmm1 - movsd qword ptr (40+24)[rsp], xmm2 - movsd qword ptr (40+32)[rsp], xmm3 -fp_spill_templates_end: -public fp_spill_templates_end - -;; The actual template function code here - -trampoline_template proc +privateSnippetExecutor proc frame ;; Make stack frame. Re-align RSP at 16 bytes. We need just one ;; qword of stack for our own purposes: Where cpp_vtable_call() @@ -113,76 +92,20 @@ trampoline_template proc ;; cpp_vtable_call()) to spill their register parameters. sub rsp, 40 -trampoline_template_prolog_end: - - jmp trampoline_template_spill_params - - ;; We store the function table (with just one entry, for this function) and - ;; the associated unwind info here at a known offset from the function start - ;; so that we don't have to know separately where it is when we need to unregister it, but - ;; can just use the known offset from the function start. - - align 4 - ;; See http://msdn.microsoft.com/en-us/library/ssa62fwe%28v=VS.90%29.aspx -trampoline_template_function_table:: -public trampoline_template_function_table - dword 0 - dword trampoline_template_end - trampoline_template - dword unwind_info - trampoline_template -unwind_info: - byte 1 - byte trampoline_template_prolog_end - trampoline_template - byte 1 - byte 0 - byte trampoline_template_prolog_end - trampoline_template - byte 42h - -trampoline_template_spill_params:: -public trampoline_template_spill_params - - ;; Spill our register parameters. In the x64 Windows calling - ;; convention the caller always has stack space allocated - ;; where the callee can spill register parameters. - - ;; The default is integer moves, that are replaced in the - ;; generated code snippet with floating-point moves for - ;; floating-point parameters. - - mov qword ptr (40+8)[rsp], rcx - nop - mov qword ptr (40+16)[rsp], rdx - nop - mov qword ptr (40+24)[rsp], r8 - nop - mov qword ptr (40+32)[rsp], r9 - nop -trampoline_template_spill_params_end:: -public trampoline_template_spill_params_end - - ;; Call cpp_vtable_call() with 3 parameters: - - ;; 1 (rcx): nFunctionIndex - ;; 2 (rdx): nVtableOffset - ;; 3 (r8): pointer to where to store return value, followed by our + .allocstack (40) + .endprolog + + ;; Call cpp_vtable_call() with 2 parameters: + + ;; 1 (rcx): nOffsetAndIndex (already put there in code generated by codeSnippet) + ;; 2 (rdx): pointer to where to store return value, followed by our ;; return address (uninteresting to cpp_vtable_call()), followed ;; by our spilled register parameters, as stored above, followed ;; by the rest of our parameters, if any. - mov rcx, 12345467890abcdeh ;; nFunctionIndex, actual value generated from - ;; parameter to codeSnippet() -trampoline_template_function_index:: -public trampoline_template_function_index + lea rdx, 32[rsp] - mov rdx, 12345467890abcdeh ;; nVtableOffset, ditto -trampoline_template_vtable_offset:: -public trampoline_template_vtable_offset - - lea r8, 32[rsp] ;; Where cpp_vtable_call() will store the return value - - mov rax, 12345467890abcdeh ;; cpp_vtable_call address, filled in by codeSnippet() -trampoline_template_cpp_vtable_call:: -public trampoline_template_cpp_vtable_call - call rax + call cpp_vtable_call ;; cpp_vtable_call() returns the typelib_TypeClass type of the ;; return value of the called UNO function @@ -202,10 +125,7 @@ Lfloat: Lepilogue: add rsp, 40 ret -trampoline_template_end:: -public trampoline_template_end - -trampoline_template endp +privateSnippetExecutor endp end diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx index 22e0c7467e15..38d48241d02c 100644 --- a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx @@ -228,10 +228,12 @@ static inline typelib_TypeClass cpp2uno_call( //================================================================================================== extern "C" typelib_TypeClass cpp_vtable_call( - sal_Int32 nFunctionIndex, - sal_Int32 nVtableOffset, + sal_Int64 nOffsetAndIndex, void ** pStack ) { + sal_Int32 nFunctionIndex = (nOffsetAndIndex & 0xFFFFFFFF); + sal_Int32 nVtableOffset = ((nOffsetAndIndex >> 32) & 0xFFFFFFFF); + // pStack points to space for return value, after which // follows our return address (uninteresting) then the spilled // integer or floating-point register parameters from the call to @@ -372,89 +374,84 @@ extern "C" typelib_TypeClass cpp_vtable_call( } //================================================================================================== -extern "C" { - -// These are actually addresses in the code compiled from codeSnippet.asm -extern char - fp_spill_templates, - fp_spill_templates_end, - trampoline_template, - trampoline_template_function_table, - trampoline_template_spill_params, - trampoline_template_spill_params_end, - trampoline_template_function_index, - trampoline_template_vtable_offset, - trampoline_template_cpp_vtable_call, - trampoline_template_end; -} -// Just the code -int const codeSnippetSize = - (int) (&trampoline_template_end - &trampoline_template); +int const codeSnippetSize = 48; + +extern "C" char privateSnippetExecutor; // This function generates the code that acts as a proxy for the UNO function to be called. // The generated code does the following: -// - Save register parametrs. +// - Spills register parameters on stack +// - Loads functionIndex and vtableOffset into scratch registers +// - Jumps to privateSnippetExecutor unsigned char * codeSnippet( unsigned char * code, char param_kind[4], - sal_Int32 functionIndex, - sal_Int32 vtableOffset, + sal_Int32 nFunctionIndex, + sal_Int32 nVtableOffset, bool bHasHiddenParam ) { - OSL_ASSERT( (&fp_spill_templates_end - &fp_spill_templates) == - (&trampoline_template_spill_params_end - &trampoline_template_spill_params) ); - - OSL_ASSERT( ((&fp_spill_templates_end - &fp_spill_templates) / 4) * 4 == - (&fp_spill_templates_end - &fp_spill_templates) ); + sal_uInt64 nOffsetAndIndex = ( ( (sal_uInt64) nVtableOffset ) << 32 ) | ( (sal_uInt64) nFunctionIndex ); + unsigned char *p = code; if ( bHasHiddenParam ) - functionIndex |= 0x80000000; - - int const one_spill_instruction_size = - (int) ((&fp_spill_templates_end - &fp_spill_templates)) / 4; + nOffsetAndIndex |= 0x80000000; - memcpy( code, &trampoline_template, codeSnippetSize ); - - for (int i = 0; i < 4; ++i) + // Spill parameters + if ( param_kind[0] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT ) { - if ( param_kind[i] == CPPU_CURRENT_NAMESPACE::REGPARAM_FLT ) - { - memcpy (&trampoline_template_spill_params + i*one_spill_instruction_size, - &fp_spill_templates + i*one_spill_instruction_size, - one_spill_instruction_size); - } + // mov qword ptr 8[rsp], rcx + *p++ = 0x48; *p++ = 0x89; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x08; + } + else + { + // movsd qword ptr 8[rsp], xmm0 + *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x44; *p++ = 0x24; *p++ = 0x08; + } + if ( param_kind[1] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT ) + { + // mov qword ptr 16[rsp], rdx + *p++ = 0x48; *p++ = 0x89; *p++ = 0x54; *p++ = 0x24; *p++ = 0x10; } + else + { + // movsd qword ptr 16[rsp], xmm1 + *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x10; + } + if ( param_kind[2] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT ) + { + // mov qword ptr 24[rsp], r8 + *p++ = 0x4C; *p++ = 0x89; *p++ = 0x44; *p++ = 0x24; *p++ = 0x18; + } + else + { + // movsd qword ptr 24[rsp], xmm2 + *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x54; *p++ = 0x24; *p++ = 0x18; + } + if ( param_kind[3] == CPPU_CURRENT_NAMESPACE::REGPARAM_INT ) + { + // mov qword ptr 32[rsp], r9 + *p++ = 0x4C;*p++ = 0x89; *p++ = 0x4C; *p++ = 0x24; *p++ = 0x20; + } + else + { + // movsd qword ptr 32[rsp], xmm3 + *p++ = 0xF2; *p++ = 0x0F; *p++ = 0x11; *p++ = 0x5C; *p++ = 0x24; *p++ = 0x20; + } + + // mov rcx, nOffsetAndIndex + *p++ = 0x48; *p++ = 0xB9; + *((sal_uInt64 *)p) = nOffsetAndIndex; p += 8; + + // mov r11, privateSnippetExecutor + *p++ = 0x49; *p++ = 0xBB; + *((void **)p) = &privateSnippetExecutor; p += 8; + + // jmp r11 + *p++ = 0x41; *p++ = 0xFF; *p++ = 0xE3; - ((sal_uInt64*) (code + (&trampoline_template_function_index - - &trampoline_template)))[-1] = - functionIndex; - ((sal_uInt64*) (code + (&trampoline_template_vtable_offset - - &trampoline_template)))[-1] = - vtableOffset; - ((void**) (code + (&trampoline_template_cpp_vtable_call - - &trampoline_template)))[-1] = - cpp_vtable_call; - - // Add unwind data for the dynamically generated function by - // calling RtlAddFunctionTable(). - - // The unwind data is inside the function code, at a fixed offset - // from the function start. See codeSnippet.asm. Actually this is - // unnecessarily complex, we could as well just allocate the - // function table dynamically. But it doesn't hurt either, I - // think. - - // The real problem now is that we need to remove the unwind data - // with RtlDeleteFunctionTable() in freeExec() in - // vtablefactory.cxx. See comment there. - - RUNTIME_FUNCTION *pFunTable = - (RUNTIME_FUNCTION *) (code + (&trampoline_template_function_table - - &trampoline_template)); - - RtlAddFunctionTable( pFunTable, 1, (DWORD64) code ); + OSL_ASSERT( p < code + codeSnippetSize ); return code + codeSnippetSize; } diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk b/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk index e813fad0c4cc..7f73ebe4bba2 100644 --- a/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/makefile.mk @@ -55,7 +55,7 @@ SLOFILES= \ $(SLO)$/uno2cpp.obj \ $(SLO)$/dllinit.obj \ $(SLO)$/except.obj \ - $(SLO)$/codeSnippet.obj + $(SLO)$/call.obj NOOPTFILES= \ $(SLO)$/except.obj diff --git a/bridges/source/cpp_uno/shared/vtablefactory.cxx b/bridges/source/cpp_uno/shared/vtablefactory.cxx index f589c295f3a7..4b819632c863 100644 --- a/bridges/source/cpp_uno/shared/vtablefactory.cxx +++ b/bridges/source/cpp_uno/shared/vtablefactory.cxx @@ -125,14 +125,6 @@ extern "C" void * SAL_CALL allocExec(rtl_arena_type *, sal_Size * size) { return p; } -#if defined SAL_W32 -extern "C" { -extern char - trampoline_template, - trampoline_template_function_table; -} -#endif - extern "C" void SAL_CALL freeExec( rtl_arena_type *, void * address, sal_Size size) { @@ -140,22 +132,6 @@ extern "C" void SAL_CALL freeExec( munmap(static_cast< char * >(address), size); #elif defined SAL_W32 (void) size; // unused - - // Remove the function table for the dynamically generated - // function that was added in codeSnippet() in cpp2uno.cxx. - -#if 0 - // This is broken. address is not the address of a code - // snippet. Each virtual memory region alocated with - // VirtualAlloc() contains multiple generated code snippets. We - // need to have a hash table from the base addresses of the region - // to the function tables inside it. - - RUNTIME_FUNCTION *pFunTable = - (RUNTIME_FUNCTION *) ((char *) address + (&trampoline_template_function_table - &trampoline_template)); - RtlDeleteFunctionTable( pFunTable ); -#endif - VirtualFree(address, 0, MEM_RELEASE); #elif defined(SAL_OS2) (void) DosFreeMem( address); |