[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