[PATCH v2] mscoree: Implement VTable fixup for x86_64 architecture.

Paul Gofman gofmanp at gmail.com
Fri Jan 22 06:01:52 CST 2016


Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
 dlls/mscoree/corruntimehost.c | 151 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 138 insertions(+), 13 deletions(-)

diff --git a/dlls/mscoree/corruntimehost.c b/dlls/mscoree/corruntimehost.c
index e437cc2..8fae477 100644
--- a/dlls/mscoree/corruntimehost.c
+++ b/dlls/mscoree/corruntimehost.c
@@ -919,7 +919,117 @@ static const struct vtable_fixup_thunk thunk_template = {
 
 #include "poppack.h"
 
-#else /* !defined(__i386__) */
+#elif __x86_64__ /* !__i386__ */
+
+# define CAN_FIXUP_VTABLE 1
+
+#include "pshpack1.h"
+
+struct vtable_fixup_thunk
+{
+    /* push %rcx; push %rdx; push %r8; push %r9 */
+    BYTE i1[6];
+    /* non-AVX:
+        sub $0x88, %rsp ; 0x10*6 + 0x20 + 0x8 (align stack for subequent func call)
+        movups %xmm0,0x20(%esp); ...; movups %xmm5,0x70(%esp)
+       AVX:
+        sub $0xE8, %rsp ; 0x20*6 + 0x20 + 0x8 (align)
+        vmovups %ymm0,0x20(%esp); ...; vmovups %ymm5,0xC0(%esp)
+
+        Using unaligned vector load/store not to depend on initial stack alignment. 
+        ReallyFixupVTable should have force_align_arg_pointer, otherwise will crash
+         on aligned xmm regs save if we are called with unaligned stack
+         (might be for some old stuff)
+    */
+    BYTE i2[58];
+    /* mov function,%eax */
+    BYTE i3[2];
+    void (CDECL *function)(struct dll_fixup *);
+    /* mov fixup,%rcx */
+    BYTE i4[2];
+    struct dll_fixup *fixup;
+    /* call *%eax */
+    BYTE i5[2];
+    /* non-AVX:
+        movups 0x20(%esp),xmm0; ...; movups 0x70(%esp),xmm5
+        add $0x88, %rsp
+       AVX:
+        vmovups 0x20(%esp),ymm0; ...; vmovups 0xC0(%esp),ymm5
+        add $0xE8, %rsp
+    */
+    BYTE i6[58];
+    /* pop %r9; pop %r8; pop %rdx; pop %rcx */
+    BYTE i7[6];
+    /* mov vtable_entry, %rax */
+    BYTE i8[2];
+    void *vtable_entry;
+    /* mov [%rax],%rax
+       jmp %rax */
+    BYTE i9[5];
+};
+
+static const struct vtable_fixup_thunk thunk_template = {
+    {0x51,0x52,0x41,0x50,0x41,0x51},
+    {0x48,0x81,0xEC,0x88,0x00,0x00,0x00,
+     0x90,0x67,0x0F,0x11,0x44,0x24,0x28,                0x90,0x67,0x0F,0x11,0x4C,0x24,0x38,
+     0x90,0x67,0x0F,0x11,0x54,0x24,0x48,                0x90,0x67,0x0F,0x11,0x5C,0x24,0x58,0x90,0x90,0x90,
+     0x90,0x67,0x0F,0x11,0x64,0x24,0x68,0x90,0x90,0x90, 0x90,0x67,0x0F,0x11,0x6C,0x24,0x78,0x90,0x90,0x90,
+    },
+    {0x48,0xB8},
+    NULL,
+    {0x48,0xB9},
+    NULL,
+    {0xFF,0xD0},
+    {0x90,0x67,0x0F,0x10,0x44,0x24,0x28,                0x90,0x67,0x0F,0x10,0x4C,0x24,0x38,
+     0x90,0x67,0x0F,0x10,0x54,0x24,0x48,                0x90,0x67,0x0F,0x10,0x5C,0x24,0x58,0x90,0x90,0x90,
+     0x90,0x67,0x0F,0x10,0x64,0x24,0x68,0x90,0x90,0x90, 0x90,0x67,0x0F,0x10,0x6C,0x24,0x78,0x90,0x90,0x90,
+     0x48,0x81,0xC4,0x88,0x00,0x00,0x00},
+    {0x41,0x59,0x41,0x58,0x5A,0x59},
+    {0x48,0xB8},
+    NULL,
+    {0x48,0x8B,0x00,0xFF,0xE0}
+};
+
+static const struct vtable_fixup_thunk thunk_template_avx = {
+    {0x51,0x52,0x41,0x50,0x41,0x51},
+    {0x48,0x81,0xEC,0xE8,0x00,0x00,0x00,
+     0x67,0xC5,0xFC,0x11,0x44,0x24,0x28,                0x67,0xC5,0xFC,0x11,0x4C,0x24,0x48,
+     0x67,0xC5,0xFC,0x11,0x54,0x24,0x68,                0x67,0xC5,0xFC,0x11,0x9C,0x24,0x88,0x00,0x00,0x00,
+     0x67,0xC5,0xFC,0x11,0xA4,0x24,0xA8,0x00,0x00,0x00, 0x67,0xC5,0xFC,0x11,0xAC,0x24,0xC8,0x00,0x00,0x00
+    },
+    {0x48,0xB8},
+    NULL,
+    {0x48,0xB9},
+    NULL,
+    {0xFF,0xD0},
+    {0x67,0xC5,0xFC,0x10,0x44,0x24,0x28,                0x67,0xC5,0xFC,0x10,0x4C,0x24,0x48,
+     0x67,0xC5,0xFC,0x10,0x54,0x24,0x68,                0x67,0xC5,0xFC,0x10,0x9C,0x24,0x88,0x00,0x00,0x00,
+     0x67,0xC5,0xFC,0x10,0xA4,0x24,0xA8,0x00,0x00,0x00, 0x67,0xC5,0xFC,0x10,0xAC,0x24,0xC8,0x00,0x00,0x00,
+     0x48,0x81,0xC4,0xE8,0x00,0x00,0x00},
+    {0x41,0x59,0x41,0x58,0x5A,0x59},
+    {0x48,0xB8},
+    NULL,
+    {0x48,0x8B,0x00,0xFF,0xE0}
+};
+
+#include "poppack.h"
+
+static int isAVXEnabled(void)
+{
+#define cpuid(func,ax,bx,cx,dx)\
+	__asm__ __volatile__ ("cpuid":\
+	"=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func));
+#define AVXFlag     (1UL<<28)
+int eax,ebx,ecx,edx;
+    cpuid(0, eax, ebx, ecx, edx);
+    if (eax < 1) return 0;
+    cpuid(1, eax, ebx, ecx, edx);
+    return (ecx & AVXFlag) != 0;
+#undef cpuid
+#undef AVXFlag
+}
+
+#else /* !__i386__ && !__x86_64__ */
 
 # define CAN_FIXUP_VTABLE 0
 
@@ -934,7 +1044,7 @@ static const struct vtable_fixup_thunk thunk_template = {0};
 
 #endif
 
-static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
+static void CDECL __attribute__((force_align_arg_pointer)) ReallyFixupVTable(struct dll_fixup *fixup)
 {
     HRESULT hr=S_OK;
     WCHAR filename[MAX_PATH];
@@ -982,15 +1092,19 @@ static void CDECL ReallyFixupVTable(struct dll_fixup *fixup)
         /* Mono needs an image that belongs to an assembly. */
         image = mono_assembly_get_image(assembly);
 
+#if __x86_64__
+        if (fixup->fixup->type & COR_VTABLE_64BIT)
+#else
         if (fixup->fixup->type & COR_VTABLE_32BIT)
+#endif
         {
-            DWORD *vtable = fixup->vtable;
-            DWORD *tokens = fixup->tokens;
+            void **vtable = fixup->vtable;
+            ULONG_PTR *tokens = fixup->tokens;
             for (i=0; i<fixup->fixup->count; i++)
             {
-                TRACE("%x\n", tokens[i]);
-                vtable[i] = PtrToUint(mono_marshal_get_vtfixup_ftnptr(
-                    image, tokens[i], fixup->fixup->type));
+                TRACE("%#lx\n", tokens[i]);
+                vtable[i] = mono_marshal_get_vtfixup_ftnptr(
+                    image, tokens[i], fixup->fixup->type);
             }
         }
 
@@ -1020,6 +1134,11 @@ static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup)
      * called while we're filling in the table, and we can never be sure all
      * threads are clear. */
     struct dll_fixup *fixup;
+#if __x86_64__
+    int have_avx;
+
+    have_avx = isAVXEnabled();
+#endif
 
     fixup = HeapAlloc(GetProcessHeap(), 0, sizeof(*fixup));
 
@@ -1029,25 +1148,31 @@ static void FixupVTableEntry(HMODULE hmodule, VTableFixup *vtable_fixup)
     fixup->vtable = (BYTE*)hmodule + vtable_fixup->rva;
     fixup->done = FALSE;
 
+    TRACE("vtable_fixup->type=0x%x\n",vtable_fixup->type);
+#if __x86_64__
+    if (vtable_fixup->type & COR_VTABLE_64BIT)
+#else
     if (vtable_fixup->type & COR_VTABLE_32BIT)
+#endif
     {
-        DWORD *vtable = fixup->vtable;
-        DWORD *tokens;
+        void **vtable = fixup->vtable;
+        ULONG_PTR *tokens;
         int i;
         struct vtable_fixup_thunk *thunks = fixup->thunk_code;
 
-        if (sizeof(void*) > 4)
-            ERR("32-bit fixup in 64-bit mode; broken image?\n");
-
         tokens = fixup->tokens = HeapAlloc(GetProcessHeap(), 0, sizeof(*tokens) * vtable_fixup->count);
         memcpy(tokens, vtable, sizeof(*tokens) * vtable_fixup->count);
         for (i=0; i<vtable_fixup->count; i++)
         {
+#if __x86_64__
+            thunks[i] = have_avx ? thunk_template_avx : thunk_template;
+#else
             thunks[i] = thunk_template;
+#endif
             thunks[i].fixup = fixup;
             thunks[i].function = ReallyFixupVTable;
             thunks[i].vtable_entry = &vtable[i];
-            vtable[i] = PtrToUint(&thunks[i]);
+            vtable[i] = &thunks[i];
         }
     }
     else
-- 
2.5.0




More information about the wine-patches mailing list