[PATCH 4/4] oleaut32: handle by-val to by-reference passing magic on x86_64
Marcus Meissner <[email protected]> Sun, 5 Nov 2017 16:00:05 +0100
| Newsgroups | gmane.comp.emulators.wine.patches |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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