Commit 439ce3a3 authored by Alexandre Julliard's avatar Alexandre Julliard

rpcrt4: Generate stubless thunks at compile time.

parent 533823ed
...@@ -82,23 +82,13 @@ __ASM_GLOBAL_FUNC(call_stubless_func, ...@@ -82,23 +82,13 @@ __ASM_GLOBAL_FUNC(call_stubless_func,
"addl %edx,%esp\n\t" "addl %edx,%esp\n\t"
"jmp *%ecx" ); "jmp *%ecx" );
#include "pshpack1.h" #define THUNK_ENTRY_SIZE 12
struct thunk #define THUNK_ENTRY(num) \
{ ".balign 4\n\t" \
BYTE mov_eax; "movl $("#num"),%eax\n\t" \
DWORD index; ".byte 0xe9\n\t" /* jmp */ \
BYTE jmp; ".long " __ASM_NAME("call_stubless_func") "-1f\n" \
LONG handler; "1:\n\t"
};
#include "poppack.h"
static inline void init_thunk( struct thunk *thunk, unsigned int index )
{
thunk->mov_eax = 0xb8; /* movl $n,%eax */
thunk->index = index;
thunk->jmp = 0xe9; /* jmp */
thunk->handler = (char *)call_stubless_func - (char *)(&thunk->handler + 1);
}
#elif defined(__x86_64__) #elif defined(__x86_64__)
...@@ -128,30 +118,13 @@ __ASM_GLOBAL_FUNC(call_stubless_func, ...@@ -128,30 +118,13 @@ __ASM_GLOBAL_FUNC(call_stubless_func,
__ASM_CFI(".cfi_adjust_cfa_offset -0x38\n\t") __ASM_CFI(".cfi_adjust_cfa_offset -0x38\n\t")
"ret" ); "ret" );
#include "pshpack1.h" #define THUNK_ENTRY_SIZE 12
struct thunk #define THUNK_ENTRY(num) \
{ ".balign 4\n\t" \
BYTE mov_r10[3]; "movl $("#num"),%r10d\n\t" \
DWORD index; ".byte 0xe9\n\t" /* jmp */ \
BYTE mov_rax[2]; ".long " __ASM_NAME("call_stubless_func") "-1f\n" \
void *call_stubless; "1:\n\t"
BYTE jmp_rax[2];
};
#include "poppack.h"
static const struct thunk thunk_template =
{
{ 0x49, 0xc7, 0xc2 }, 0, /* movq $index,%r10 */
{ 0x48, 0xb8 }, 0, /* movq $call_stubless_func,%rax */
{ 0xff, 0xe0 } /* jmp *%rax */
};
static inline void init_thunk( struct thunk *thunk, unsigned int index )
{
*thunk = thunk_template;
thunk->index = index;
thunk->call_stubless = call_stubless_func;
}
#elif defined(__arm__) #elif defined(__arm__)
...@@ -180,21 +153,11 @@ __ASM_GLOBAL_FUNC(call_stubless_func, ...@@ -180,21 +153,11 @@ __ASM_GLOBAL_FUNC(call_stubless_func,
"add sp, #16\n\t" "add sp, #16\n\t"
"bx lr" ); "bx lr" );
struct thunk #define THUNK_ENTRY_SIZE 12
{ #define THUNK_ENTRY(num) \
DWORD ldr_ip; /* ldr ip,[pc] */ "ldr ip,1f\n\t" \
DWORD ldr_pc; /* ldr pc,[pc] */ "b.w " __ASM_NAME("call_stubless_func") "\n" \
DWORD index; "1:\t.long "#num"\n\t"
void *func;
};
static inline void init_thunk( struct thunk *thunk, unsigned int index )
{
thunk->ldr_ip = 0xe59fc000; /* ldr ip,[pc] */
thunk->ldr_pc = 0xe59ff000; /* ldr pc,[pc] */
thunk->index = index * sizeof(unsigned short);
thunk->func = call_stubless_func;
}
#elif defined(__aarch64__) #elif defined(__aarch64__)
...@@ -225,83 +188,37 @@ __ASM_GLOBAL_FUNC( call_stubless_func, ...@@ -225,83 +188,37 @@ __ASM_GLOBAL_FUNC( call_stubless_func,
"ldp x29, x30, [sp], #0x90\n\t" "ldp x29, x30, [sp], #0x90\n\t"
"ret" ) "ret" )
struct thunk #define THUNK_ENTRY_SIZE 8
{ #define THUNK_ENTRY(num) \
DWORD ldr_index; /* ldr w16, index */ "mov w16,#("#num")\n\t" \
DWORD ldr_func; /* ldr x17, func */ "b " __ASM_NAME("call_stubless_func") "\n\t"
DWORD br; /* br x17 */
DWORD index;
void *func;
};
static inline void init_thunk( struct thunk *thunk, unsigned int index )
{
thunk->ldr_index = 0x18000070; /* ldr w16,index */
thunk->ldr_func = 0x58000071; /* ldr x17,func */
thunk->br = 0xd61f0220; /* br x17 */
thunk->index = index;
thunk->func = call_stubless_func;
}
#else /* __i386__ */ #else /* __i386__ */
#warning You must implement stubless proxies for your CPU #warning You must implement stubless proxies for your CPU
struct thunk #define THUNK_ENTRY_SIZE 0
{ #define THUNK_ENTRY(num) ""
DWORD index;
};
static inline void init_thunk( struct thunk *thunk, unsigned int index )
{
thunk->index = index;
}
#endif /* __i386__ */ #endif /* __i386__ */
#define BLOCK_SIZE 1024 extern void stubless_thunks(void);
#define MAX_BLOCKS 64 /* 64k methods should be enough for anybody */ __ASM_GLOBAL_FUNC( stubless_thunks, ALL_THUNK_ENTRIES )
#undef THUNK_ENTRY
static const struct thunk *method_blocks[MAX_BLOCKS];
static const struct thunk *allocate_block( unsigned int num )
{
unsigned int i;
struct thunk *prev, *block;
DWORD oldprot;
block = VirtualAlloc( NULL, BLOCK_SIZE * sizeof(*block),
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );
if (!block) return NULL;
for (i = 0; i < BLOCK_SIZE; i++) init_thunk( &block[i], BLOCK_SIZE * num + i + 3 );
VirtualProtect( block, BLOCK_SIZE * sizeof(*block), PAGE_EXECUTE_READ, &oldprot );
prev = InterlockedCompareExchangePointer( (void **)&method_blocks[num], block, NULL );
if (prev) /* someone beat us to it */
{
VirtualFree( block, 0, MEM_RELEASE );
block = prev;
}
return block;
}
BOOL fill_stubless_table( IUnknownVtbl *vtbl, DWORD num ) BOOL fill_stubless_table( IUnknownVtbl *vtbl, DWORD num )
{ {
const void **entry = (const void **)(vtbl + 1); const void **entry = (const void **)(vtbl + 1);
DWORD i, j; DWORD i;
if (num - 3 > BLOCK_SIZE * MAX_BLOCKS) if (num >= NB_THUNK_ENTRIES)
{ {
FIXME( "%lu methods not supported\n", num ); FIXME( "%lu methods not supported\n", num );
return FALSE; return FALSE;
} }
for (i = 0; i < (num - 3 + BLOCK_SIZE - 1) / BLOCK_SIZE; i++) for (i = 0; i < num - 3; i++, entry++)
{ if (*entry == (void *)-1) *entry = (char *)stubless_thunks + i * THUNK_ENTRY_SIZE;
const struct thunk *block = method_blocks[i];
if (!block && !(block = allocate_block( i ))) return FALSE;
for (j = 0; j < BLOCK_SIZE && j < num - 3 - i * BLOCK_SIZE; j++, entry++)
if (*entry == (LPVOID)-1) *entry = &block[j];
}
return TRUE; return TRUE;
} }
......
...@@ -72,4 +72,105 @@ BOOL fill_stubless_table(IUnknownVtbl *vtbl, DWORD num) DECLSPEC_HIDDEN; ...@@ -72,4 +72,105 @@ BOOL fill_stubless_table(IUnknownVtbl *vtbl, DWORD num) DECLSPEC_HIDDEN;
IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) DECLSPEC_HIDDEN; IUnknownVtbl *get_delegating_vtbl(DWORD num_methods) DECLSPEC_HIDDEN;
void release_delegating_vtbl(IUnknownVtbl *vtbl) DECLSPEC_HIDDEN; void release_delegating_vtbl(IUnknownVtbl *vtbl) DECLSPEC_HIDDEN;
#define THUNK_ENTRY_FIRST_BLOCK() \
THUNK_ENTRY(3) \
THUNK_ENTRY(4) \
THUNK_ENTRY(5) \
THUNK_ENTRY(6) \
THUNK_ENTRY(7) \
THUNK_ENTRY(8) \
THUNK_ENTRY(9) \
THUNK_ENTRY(10) \
THUNK_ENTRY(11) \
THUNK_ENTRY(12) \
THUNK_ENTRY(13) \
THUNK_ENTRY(14) \
THUNK_ENTRY(15) \
THUNK_ENTRY(16) \
THUNK_ENTRY(17) \
THUNK_ENTRY(18) \
THUNK_ENTRY(19) \
THUNK_ENTRY(20) \
THUNK_ENTRY(21) \
THUNK_ENTRY(22) \
THUNK_ENTRY(23) \
THUNK_ENTRY(24) \
THUNK_ENTRY(25) \
THUNK_ENTRY(26) \
THUNK_ENTRY(27) \
THUNK_ENTRY(28) \
THUNK_ENTRY(29) \
THUNK_ENTRY(30) \
THUNK_ENTRY(31)
#define THUNK_ENTRY_BLOCK(block) \
THUNK_ENTRY(32 * (block) + 0) \
THUNK_ENTRY(32 * (block) + 1) \
THUNK_ENTRY(32 * (block) + 2) \
THUNK_ENTRY(32 * (block) + 3) \
THUNK_ENTRY(32 * (block) + 4) \
THUNK_ENTRY(32 * (block) + 5) \
THUNK_ENTRY(32 * (block) + 6) \
THUNK_ENTRY(32 * (block) + 7) \
THUNK_ENTRY(32 * (block) + 8) \
THUNK_ENTRY(32 * (block) + 9) \
THUNK_ENTRY(32 * (block) + 10) \
THUNK_ENTRY(32 * (block) + 11) \
THUNK_ENTRY(32 * (block) + 12) \
THUNK_ENTRY(32 * (block) + 13) \
THUNK_ENTRY(32 * (block) + 14) \
THUNK_ENTRY(32 * (block) + 15) \
THUNK_ENTRY(32 * (block) + 16) \
THUNK_ENTRY(32 * (block) + 17) \
THUNK_ENTRY(32 * (block) + 18) \
THUNK_ENTRY(32 * (block) + 19) \
THUNK_ENTRY(32 * (block) + 20) \
THUNK_ENTRY(32 * (block) + 21) \
THUNK_ENTRY(32 * (block) + 22) \
THUNK_ENTRY(32 * (block) + 23) \
THUNK_ENTRY(32 * (block) + 24) \
THUNK_ENTRY(32 * (block) + 25) \
THUNK_ENTRY(32 * (block) + 26) \
THUNK_ENTRY(32 * (block) + 27) \
THUNK_ENTRY(32 * (block) + 28) \
THUNK_ENTRY(32 * (block) + 29) \
THUNK_ENTRY(32 * (block) + 30) \
THUNK_ENTRY(32 * (block) + 31)
#define ALL_THUNK_ENTRIES \
THUNK_ENTRY_FIRST_BLOCK() \
THUNK_ENTRY_BLOCK(1) \
THUNK_ENTRY_BLOCK(2) \
THUNK_ENTRY_BLOCK(3) \
THUNK_ENTRY_BLOCK(4) \
THUNK_ENTRY_BLOCK(5) \
THUNK_ENTRY_BLOCK(6) \
THUNK_ENTRY_BLOCK(7) \
THUNK_ENTRY_BLOCK(8) \
THUNK_ENTRY_BLOCK(9) \
THUNK_ENTRY_BLOCK(10) \
THUNK_ENTRY_BLOCK(11) \
THUNK_ENTRY_BLOCK(12) \
THUNK_ENTRY_BLOCK(13) \
THUNK_ENTRY_BLOCK(14) \
THUNK_ENTRY_BLOCK(15) \
THUNK_ENTRY_BLOCK(16) \
THUNK_ENTRY_BLOCK(17) \
THUNK_ENTRY_BLOCK(18) \
THUNK_ENTRY_BLOCK(19) \
THUNK_ENTRY_BLOCK(20) \
THUNK_ENTRY_BLOCK(21) \
THUNK_ENTRY_BLOCK(22) \
THUNK_ENTRY_BLOCK(23) \
THUNK_ENTRY_BLOCK(24) \
THUNK_ENTRY_BLOCK(25) \
THUNK_ENTRY_BLOCK(26) \
THUNK_ENTRY_BLOCK(27) \
THUNK_ENTRY_BLOCK(28) \
THUNK_ENTRY_BLOCK(29) \
THUNK_ENTRY_BLOCK(30) \
THUNK_ENTRY_BLOCK(31)
#define NB_THUNK_ENTRIES (32 * 32)
#endif /* __WINE_CPSF_H */ #endif /* __WINE_CPSF_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment