[PATCH 4/4] oleaut32: handle by-val to by-reference passing magic on x86_64

Marcus Meissner marcus at jet.franken.de
Sun Nov 5 09:00:05 CST 2017


The Win64 API does not pass structures on the stack, but implicit
by reference. Handle this during the generated stub/proxy calls.

Also changed argsize to always return 1 on x86_64 due to this.

Signed-off-by: Marcus Meissner <marcus at jet.franken.de>
---
 dlls/oleaut32/tmarshal.c | 77 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 69 insertions(+), 8 deletions(-)

diff --git a/dlls/oleaut32/tmarshal.c b/dlls/oleaut32/tmarshal.c
index e71e9771f4..30506468d0 100644
--- a/dlls/oleaut32/tmarshal.c
+++ b/dlls/oleaut32/tmarshal.c
@@ -135,16 +135,16 @@ _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
     DWORD		xsize;
 
     TRACE("...%s...\n",debugstr_guid(riid));
-    
+
     *pUnk = NULL;
     hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
     if (hres) {
         ERR("xbuf_get failed\n");
         return hres;
     }
-    
+
     if (xsize == 0) return S_OK;
-    
+
     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
     if (hres) {
 	ERR("Stream create failed %x\n",hres);
@@ -660,6 +660,7 @@ static const IRpcProxyBufferVtbl tmproxyvtable = {
 /* how much space do we use on stack in DWORD_PTR steps. */
 static int
 _argsize(TYPEDESC *tdesc, ITypeInfo *tinfo) {
+#ifdef __i386__
     DWORD ret;
     switch (tdesc->vt) {
     case VT_I8:
@@ -702,6 +703,11 @@ _argsize(TYPEDESC *tdesc, ITypeInfo *tinfo) {
     }
 
     return (ret + sizeof(DWORD_PTR) - 1) / sizeof(DWORD_PTR);
+#else
+    /* On x86_64 we do not store byvalue things on the stack, everything
+     * larger than a register will be spilled and passed by reference */
+    return 1;
+#endif
 }
 
 /* how much space do we use on the heap (in bytes) */
@@ -749,6 +755,9 @@ _xsize(const TYPEDESC *td, ITypeInfo *tinfo) {
         ITypeInfo_Release(tinfo2);
         return ret;
     }
+    case VT_UINT:
+    case VT_INT:
+        return 4;
     default:
 	return sizeof(DWORD_PTR);
     }
@@ -888,6 +897,7 @@ serialize_param(
                 }
                 break;
 	    case TKIND_ENUM:	/* confirmed */
+		break;
 	    case TKIND_RECORD:	/* FIXME: mostly untested */
 		break;
 	    case TKIND_DISPATCH:	/* will be done in VT_USERDEFINED case */
@@ -1458,7 +1468,7 @@ static DWORD WINAPI xCall(int method, void **args)
     UINT		nrofnames;
     DWORD		remoteresult = 0;
     ITypeInfo 		*tinfo;
-    IRpcChannelBuffer *chanbuf;
+    IRpcChannelBuffer	*chanbuf;
 
     EnterCriticalSection(&tpinfo->crit);
 
@@ -1509,6 +1519,8 @@ static DWORD WINAPI xCall(int method, void **args)
     xargs = (DWORD_PTR *)(args + 1);
     for (i=0;i<fdesc->cParams;i++) {
 	ELEMDESC	*elem = fdesc->lprgelemdescParam+i;
+	DWORD_PTR	*argsptr;
+
 	if (TRACE_ON(olerelay)) {
 	    if (i) TRACE_(olerelay)(",");
 	    if (i+1<nrofnames && names[i+1])
@@ -1529,13 +1541,21 @@ static DWORD WINAPI xCall(int method, void **args)
             }
         }
 
+	argsptr = xargs;
+#ifdef __x86_64__
+	/* On win64 the passing of structs by value does implicit pass a ptr to the struct anyway */
+	/* FIXME: only checked for USERDEFINED */
+	if (elem->tdesc.vt == VT_USERDEFINED)
+	    argsptr = *(DWORD_PTR**)xargs;
+#endif
+
 	hres = serialize_param(
 	    tinfo,
 	    is_in_elem(elem),
 	    TRACE_ON(olerelay),
 	    FALSE,
 	    &elem->tdesc,
-	    xargs,
+	    argsptr,
 	    &buf
 	);
 
@@ -1577,6 +1597,7 @@ static DWORD WINAPI xCall(int method, void **args)
     status = S_OK;
     for (i=0;i<fdesc->cParams;i++) {
 	ELEMDESC	*elem = fdesc->lprgelemdescParam+i;
+	DWORD_PTR	*argsptr;
 
         if (i) TRACE_(olerelay)(",");
         if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
@@ -1587,13 +1608,20 @@ static DWORD WINAPI xCall(int method, void **args)
 	    TRACE_(olerelay)("[in]");
 	    continue;
 	}
+
+	argsptr = xargs;
+#ifdef __x86_64__
+	/* structs are implicit by-reference instead of by-val */
+	if (elem->tdesc.vt == VT_USERDEFINED)
+            argsptr = *(DWORD_PTR**)xargs;
+#endif
 	hres = deserialize_param(
 	    tinfo,
 	    is_out_elem(elem),
 	    TRACE_ON(olerelay),
 	    FALSE,
 	    &(elem->tdesc),
-	    xargs,
+	    argsptr,
 	    &buf
         );
 	if (hres) {
@@ -1872,6 +1900,21 @@ static HRESULT init_proxy_entry_point(TMProxyImpl *proxy, unsigned int num)
 
 #elif defined(__x86_64__)
 
+/* Stack layout:
+ * We store the 4 register arguments in the supplied "register save zone"
+ * so all arguments line up on the stack, same as in i386 mode.
+ * ... further args ...
+ * arg6
+ * arg5
+ * zone0	8	+0x28 arg4
+ * zone0	8	+0x20 arg3
+ * zone0	8	+0x18 arg2
+ * zone0	8	+0x10 arg1	< %RDX (arg2) before call
+ * return RIP	8
+ * saved RBP	8	<= RBP in assembler stub
+ * ..
+ */
+
     xasm->pushq_rbp         = 0x55;         /* pushq %rbp */
     xasm->movq_rsp_rbp[0]   = 0x48;         /* movq %rsp,%rbp */
     xasm->movq_rsp_rbp[1]   = 0x89;
@@ -2205,6 +2248,16 @@ TMStubImpl_Invoke(
     xargs = args+1;
     for (i=0;i<fdesc->cParams;i++) {
 	ELEMDESC	*elem = fdesc->lprgelemdescParam+i;
+	DWORD_PTR	*argsptr;
+
+	argsptr = xargs;
+#ifdef __x86_64__
+	/* structs are implicit by-reference instead of by-val */
+	if (elem->tdesc.vt == VT_USERDEFINED) {
+            *xargs = (DWORD_PTR)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(&elem->tdesc, tinfo));
+            argsptr = *(DWORD_PTR**)xargs;
+        }
+#endif
 
 	hres = deserialize_param(
 	   tinfo,
@@ -2212,7 +2265,7 @@ TMStubImpl_Invoke(
 	   FALSE,
 	   TRUE,
 	   &(elem->tdesc),
-	   xargs,
+	   argsptr,
 	   &buf
 	);
 	xargs += _argsize(&elem->tdesc, tinfo);
@@ -2252,13 +2305,21 @@ TMStubImpl_Invoke(
     xargs = args+1;
     for (i=0;i<fdesc->cParams;i++) {
 	ELEMDESC	*elem = fdesc->lprgelemdescParam+i;
+	DWORD_PTR	*argsptr;
+
+	argsptr = xargs;
+#ifdef __x86_64__
+	/* structs are implicit by-reference instead of by-val */
+	if (elem->tdesc.vt == VT_USERDEFINED)
+            argsptr = *(DWORD_PTR**)xargs;
+#endif
 	hres = serialize_param(
 	   tinfo,
 	   is_out_elem(elem),
 	   FALSE,
 	   TRUE,
 	   &elem->tdesc,
-	   xargs,
+	   argsptr,
 	   &buf
 	);
 	xargs += _argsize(&elem->tdesc, tinfo);
-- 
2.14.3




More information about the wine-patches mailing list