mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 20:07:17 +00:00
rpcrt4: Fix stack alignment and by-value parameters for typelibs on ARM platforms.
This commit is contained in:
parent
d07019e4d1
commit
486068560e
|
@ -43,6 +43,7 @@ static size_t write_type_tfs(ITypeInfo *typeinfo, unsigned char *str,
|
|||
do { if ((str)) *((short *)((str) + (len))) = (val); (len) += 2; } while (0)
|
||||
#define WRITE_INT(str, len, val) \
|
||||
do { if ((str)) *((int *)((str) + (len))) = (val); (len) += 4; } while (0)
|
||||
#define ROUND_SIZE(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1))
|
||||
|
||||
extern const ExtendedProxyFileInfo ndr_types_ProxyFileInfo;
|
||||
|
||||
|
@ -145,17 +146,21 @@ static unsigned char get_basetype(ITypeInfo *typeinfo, TYPEDESC *desc)
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned int type_memsize(ITypeInfo *typeinfo, TYPEDESC *desc)
|
||||
static unsigned int type_memsize(ITypeInfo *typeinfo, TYPEDESC *desc, unsigned int *align_ret)
|
||||
{
|
||||
unsigned int size, align;
|
||||
|
||||
switch (desc->vt)
|
||||
{
|
||||
case VT_I1:
|
||||
case VT_UI1:
|
||||
return 1;
|
||||
size = align = 1;
|
||||
break;
|
||||
case VT_I2:
|
||||
case VT_UI2:
|
||||
case VT_BOOL:
|
||||
return 2;
|
||||
size = align = 2;
|
||||
break;
|
||||
case VT_I4:
|
||||
case VT_UI4:
|
||||
case VT_R4:
|
||||
|
@ -163,45 +168,52 @@ static unsigned int type_memsize(ITypeInfo *typeinfo, TYPEDESC *desc)
|
|||
case VT_UINT:
|
||||
case VT_ERROR:
|
||||
case VT_HRESULT:
|
||||
return 4;
|
||||
size = align = 4;
|
||||
break;
|
||||
case VT_I8:
|
||||
case VT_UI8:
|
||||
case VT_R8:
|
||||
case VT_DATE:
|
||||
return 8;
|
||||
size = align = 8;
|
||||
break;
|
||||
case VT_BSTR:
|
||||
case VT_SAFEARRAY:
|
||||
case VT_PTR:
|
||||
case VT_UNKNOWN:
|
||||
case VT_DISPATCH:
|
||||
return sizeof(void *);
|
||||
size = align = sizeof(void *);
|
||||
break;
|
||||
case VT_VARIANT:
|
||||
return sizeof(VARIANT);
|
||||
align = 8;
|
||||
size = sizeof(VARIANT);
|
||||
break;
|
||||
case VT_CARRAY:
|
||||
{
|
||||
unsigned int size = type_memsize(typeinfo, &desc->lpadesc->tdescElem);
|
||||
unsigned int i;
|
||||
size = type_memsize(typeinfo, &desc->lpadesc->tdescElem, &align);
|
||||
for (i = 0; i < desc->lpadesc->cDims; i++)
|
||||
size *= desc->lpadesc->rgbounds[i].cElements;
|
||||
return size;
|
||||
break;
|
||||
}
|
||||
case VT_USERDEFINED:
|
||||
{
|
||||
unsigned int size = 0;
|
||||
ITypeInfo *refinfo;
|
||||
TYPEATTR *attr;
|
||||
|
||||
ITypeInfo_GetRefTypeInfo(typeinfo, desc->hreftype, &refinfo);
|
||||
ITypeInfo_GetTypeAttr(refinfo, &attr);
|
||||
size = attr->cbSizeInstance;
|
||||
align = attr->cbAlignment;
|
||||
ITypeInfo_ReleaseTypeAttr(refinfo, attr);
|
||||
ITypeInfo_Release(refinfo);
|
||||
return size;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FIXME("unhandled type %u\n", desc->vt);
|
||||
return 0;
|
||||
}
|
||||
if (align_ret) *align_ret = align;
|
||||
return size;
|
||||
}
|
||||
|
||||
static BOOL type_pointer_is_iface(ITypeInfo *typeinfo, TYPEDESC *tdesc)
|
||||
|
@ -400,16 +412,9 @@ static void write_struct_members(ITypeInfo *typeinfo, unsigned char *str,
|
|||
ITypeInfo_GetVarDesc(typeinfo, i, &desc);
|
||||
tdesc = &desc->elemdescVar.tdesc;
|
||||
|
||||
/* This may not match the intended alignment, but we don't have enough
|
||||
* information to determine that. This should always give the correct
|
||||
* layout. */
|
||||
if ((struct_offset & 7) && !(desc->oInst & 7))
|
||||
WRITE_CHAR(str, *len, FC_ALIGNM8);
|
||||
else if ((struct_offset & 3) && !(desc->oInst & 3))
|
||||
WRITE_CHAR(str, *len, FC_ALIGNM4);
|
||||
else if ((struct_offset & 1) && !(desc->oInst & 1))
|
||||
WRITE_CHAR(str, *len, FC_ALIGNM2);
|
||||
struct_offset = desc->oInst + type_memsize(typeinfo, tdesc);
|
||||
if (struct_offset != desc->oInst)
|
||||
WRITE_CHAR(str, *len, FC_STRUCTPAD1 + desc->oInst - struct_offset - 1);
|
||||
struct_offset = desc->oInst + type_memsize(typeinfo, tdesc, NULL);
|
||||
|
||||
if ((basetype = get_basetype(typeinfo, tdesc)))
|
||||
WRITE_CHAR(str, *len, basetype);
|
||||
|
@ -570,7 +575,7 @@ static void write_complex_struct_tfs(ITypeInfo *typeinfo, unsigned char *str,
|
|||
|
||||
if (struct_offset != desc->oInst)
|
||||
member_layout++; /* alignment directive */
|
||||
struct_offset = desc->oInst + type_memsize(typeinfo, tdesc);
|
||||
struct_offset = desc->oInst + type_memsize(typeinfo, tdesc, NULL);
|
||||
|
||||
if (get_basetype(typeinfo, tdesc))
|
||||
member_layout++;
|
||||
|
@ -646,7 +651,7 @@ static size_t write_array_tfs(ITypeInfo *typeinfo, unsigned char *str,
|
|||
}
|
||||
else
|
||||
{
|
||||
size *= type_memsize(typeinfo, &desc->tdescElem);
|
||||
size *= type_memsize(typeinfo, &desc->tdescElem, NULL);
|
||||
WRITE_INT(str, *len, size);
|
||||
}
|
||||
|
||||
|
@ -846,15 +851,52 @@ static size_t write_type_tfs(ITypeInfo *typeinfo, unsigned char *str,
|
|||
return off;
|
||||
}
|
||||
|
||||
static unsigned short get_stack_size(ITypeInfo *typeinfo, TYPEDESC *desc)
|
||||
static unsigned int get_stack_size(ITypeInfo *typeinfo, TYPEDESC *desc, unsigned int *align, int *by_value)
|
||||
{
|
||||
#if defined(__i386__) || defined(__arm__)
|
||||
if (desc->vt == VT_CARRAY)
|
||||
return sizeof(void *);
|
||||
return (type_memsize(typeinfo, desc) + 3) & ~3;
|
||||
#else
|
||||
return sizeof(void *);
|
||||
unsigned int size = *align = sizeof(void *);
|
||||
int byval = 1;
|
||||
|
||||
switch (desc->vt)
|
||||
{
|
||||
case VT_R8:
|
||||
case VT_I8:
|
||||
case VT_UI8:
|
||||
case VT_DATE:
|
||||
#ifdef __arm__
|
||||
case VT_R4:
|
||||
*align = 8;
|
||||
#endif
|
||||
size = 8;
|
||||
break;
|
||||
case VT_PTR:
|
||||
case VT_UNKNOWN:
|
||||
case VT_DISPATCH:
|
||||
case VT_CARRAY:
|
||||
byval = 0;
|
||||
break;
|
||||
case VT_VARIANT:
|
||||
case VT_USERDEFINED:
|
||||
size = type_memsize(typeinfo, desc, align);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
*align = sizeof(void *);
|
||||
#endif
|
||||
if (byval)
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
byval = (size == 1 || size == 2 || size == 4 || size == 8);
|
||||
#elif defined __aarch64__
|
||||
byval = (size <= 16);
|
||||
#endif
|
||||
}
|
||||
if (!byval) size = *align = sizeof(void *);
|
||||
else if (*align < sizeof(void *)) *align = sizeof(void *);
|
||||
if (by_value) *by_value = byval;
|
||||
return ROUND_SIZE( size, *align );
|
||||
}
|
||||
|
||||
static const unsigned short MustSize = 0x0001;
|
||||
|
@ -894,7 +936,7 @@ static HRESULT get_param_pointer_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int
|
|||
break;
|
||||
case VT_CARRAY:
|
||||
*flags |= IsSimpleRef | MustFree;
|
||||
*server_size = type_memsize(typeinfo, tdesc);
|
||||
*server_size = type_memsize(typeinfo, tdesc, NULL);
|
||||
*tfs_tdesc = tdesc;
|
||||
break;
|
||||
case VT_USERDEFINED:
|
||||
|
@ -937,7 +979,7 @@ static HRESULT get_param_pointer_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int
|
|||
*flags |= IsSimpleRef;
|
||||
*tfs_tdesc = tdesc;
|
||||
if (!is_in && is_out)
|
||||
*server_size = type_memsize(typeinfo, tdesc);
|
||||
*server_size = type_memsize(typeinfo, tdesc, NULL);
|
||||
if ((*basetype = get_basetype(typeinfo, tdesc)))
|
||||
*flags |= IsBasetype;
|
||||
else
|
||||
|
@ -949,7 +991,7 @@ static HRESULT get_param_pointer_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int
|
|||
}
|
||||
|
||||
static HRESULT get_param_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int is_in,
|
||||
int is_out, unsigned short *server_size, unsigned short *flags,
|
||||
int is_out, int by_val, unsigned short *server_size, unsigned short *flags,
|
||||
unsigned char *basetype, TYPEDESC **tfs_tdesc)
|
||||
{
|
||||
ITypeInfo *refinfo;
|
||||
|
@ -966,15 +1008,10 @@ static HRESULT get_param_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int is_in,
|
|||
switch (tdesc->vt)
|
||||
{
|
||||
case VT_VARIANT:
|
||||
#if !defined(__i386__) && !defined(__arm__)
|
||||
*flags |= IsSimpleRef | MustFree;
|
||||
break;
|
||||
#endif
|
||||
/* otherwise fall through */
|
||||
case VT_BSTR:
|
||||
case VT_SAFEARRAY:
|
||||
case VT_CY:
|
||||
*flags |= IsByValue | MustFree;
|
||||
*flags |= (by_val ? IsByValue : IsSimpleRef) | MustFree;
|
||||
break;
|
||||
case VT_UNKNOWN:
|
||||
case VT_DISPATCH:
|
||||
|
@ -995,17 +1032,10 @@ static HRESULT get_param_info(ITypeInfo *typeinfo, TYPEDESC *tdesc, int is_in,
|
|||
*basetype = FC_ENUM32;
|
||||
break;
|
||||
case TKIND_RECORD:
|
||||
#if defined(__i386__) || defined(__arm__)
|
||||
*flags |= IsByValue | MustFree;
|
||||
#else
|
||||
if (attr->cbSizeInstance <= 8)
|
||||
*flags |= IsByValue | MustFree;
|
||||
else
|
||||
*flags |= IsSimpleRef | MustFree;
|
||||
#endif
|
||||
*flags |= (by_val ? IsByValue : IsSimpleRef) | MustFree;
|
||||
break;
|
||||
case TKIND_ALIAS:
|
||||
hr = get_param_info(refinfo, &attr->tdescAlias, is_in, is_out,
|
||||
hr = get_param_info(refinfo, &attr->tdescAlias, is_in, is_out, 0,
|
||||
server_size, flags, basetype, tfs_tdesc);
|
||||
break;
|
||||
|
||||
|
@ -1046,7 +1076,8 @@ static HRESULT write_param_fs(ITypeInfo *typeinfo, unsigned char *type,
|
|||
USHORT param_flags = desc->paramdesc.wParamFlags;
|
||||
TYPEDESC *tdesc = &desc->tdesc, *tfs_tdesc;
|
||||
unsigned short server_size;
|
||||
unsigned short stack_size = get_stack_size(typeinfo, tdesc);
|
||||
int byval;
|
||||
unsigned int align, stack_size = get_stack_size(typeinfo, tdesc, &align, &byval);
|
||||
unsigned char basetype;
|
||||
unsigned short flags;
|
||||
int is_in, is_out;
|
||||
|
@ -1056,7 +1087,7 @@ static HRESULT write_param_fs(ITypeInfo *typeinfo, unsigned char *type,
|
|||
is_out = param_flags & PARAMFLAG_FOUT;
|
||||
is_in = (param_flags & PARAMFLAG_FIN) || (!is_out && !is_return);
|
||||
|
||||
hr = get_param_info(typeinfo, tdesc, is_in, is_out, &server_size, &flags,
|
||||
hr = get_param_info(typeinfo, tdesc, is_in, is_out, byval, &server_size, &flags,
|
||||
&basetype, &tfs_tdesc);
|
||||
|
||||
if (is_in) flags |= IsIn;
|
||||
|
@ -1072,6 +1103,8 @@ static HRESULT write_param_fs(ITypeInfo *typeinfo, unsigned char *type,
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
*stack_offset = ROUND_SIZE( *stack_offset, align );
|
||||
|
||||
WRITE_SHORT(proc, *proclen, flags);
|
||||
WRITE_SHORT(proc, *proclen, *stack_offset);
|
||||
WRITE_SHORT(proc, *proclen, basetype ? basetype : off);
|
||||
|
@ -1085,18 +1118,23 @@ static HRESULT write_param_fs(ITypeInfo *typeinfo, unsigned char *type,
|
|||
static void write_proc_func_header(ITypeInfo *typeinfo, FUNCDESC *desc,
|
||||
WORD proc_idx, unsigned char *proc, size_t *proclen)
|
||||
{
|
||||
unsigned short stack_size = 2 * sizeof(void *); /* This + return */
|
||||
unsigned int i, align, size, stack_size = sizeof(void *); /* This */
|
||||
#ifdef __x86_64__
|
||||
unsigned short float_mask = 0;
|
||||
unsigned char basetype;
|
||||
#endif
|
||||
WORD param_idx;
|
||||
|
||||
for (i = 0; i < desc->cParams; i++)
|
||||
{
|
||||
size = get_stack_size(typeinfo, &desc->lprgelemdescParam[i].tdesc, &align, NULL );
|
||||
stack_size = ROUND_SIZE( stack_size, align );
|
||||
stack_size += size;
|
||||
}
|
||||
stack_size += sizeof(void *); /* return */
|
||||
|
||||
WRITE_CHAR (proc, *proclen, FC_AUTO_HANDLE);
|
||||
WRITE_CHAR (proc, *proclen, Oi_OBJECT_PROC | Oi_OBJ_USE_V2_INTERPRETER);
|
||||
WRITE_SHORT(proc, *proclen, proc_idx);
|
||||
for (param_idx = 0; param_idx < desc->cParams; param_idx++)
|
||||
stack_size += get_stack_size(typeinfo, &desc->lprgelemdescParam[param_idx].tdesc);
|
||||
WRITE_SHORT(proc, *proclen, stack_size);
|
||||
|
||||
WRITE_SHORT(proc, *proclen, 0); /* constant_client_buffer_size */
|
||||
|
@ -1113,13 +1151,11 @@ static void write_proc_func_header(ITypeInfo *typeinfo, FUNCDESC *desc,
|
|||
WRITE_SHORT(proc, *proclen, 0); /* ServerCorrHint */
|
||||
WRITE_SHORT(proc, *proclen, 0); /* NotifyIndex */
|
||||
#ifdef __x86_64__
|
||||
for (param_idx = 0; param_idx < desc->cParams && param_idx < 3; param_idx++)
|
||||
for (i = 0; i < desc->cParams && i < 3; i++)
|
||||
{
|
||||
basetype = get_basetype(typeinfo, &desc->lprgelemdescParam[param_idx].tdesc);
|
||||
if (basetype == FC_FLOAT)
|
||||
float_mask |= (1 << ((param_idx + 1) * 2));
|
||||
else if (basetype == FC_DOUBLE)
|
||||
float_mask |= (2 << ((param_idx + 1) * 2));
|
||||
basetype = get_basetype(typeinfo, &desc->lprgelemdescParam[i].tdesc);
|
||||
if (basetype == FC_FLOAT) float_mask |= (1 << ((i + 1) * 2));
|
||||
else if (basetype == FC_DOUBLE) float_mask |= (2 << ((i + 1) * 2));
|
||||
}
|
||||
WRITE_SHORT(proc, *proclen, float_mask);
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue