# HG changeset patch # User Tassilo Philipp # Date 1654018174 -7200 # Node ID ba70fb631bea8bc97c0b816539676c1a6a029597 # Parent ca28e9e3c644f103c4379b264de7374104596ccf x64: * support for non-standard aggr-by-value packing (#pragma pack, etc.) * callbacks: handling callconv prefixes in signature diff -r ca28e9e3c644 -r ba70fb631bea dyncall/dyncall_aggregate.c --- a/dyncall/dyncall_aggregate.c Tue May 31 18:35:06 2022 +0200 +++ b/dyncall/dyncall_aggregate.c Tue May 31 19:29:34 2022 +0200 @@ -48,6 +48,7 @@ DCaggr* ag = (DCaggr*)dcAllocMem(sizeof(DCaggr) + maxFieldCount * sizeof(DCfield)); ag->n_fields = 0; ag->size = size; + ag->alignment = 0; return ag; } @@ -83,11 +84,19 @@ va_end(ap); f->size = f->sub_aggr->size; + f->alignment = f->sub_aggr->alignment; break; } default: assert(0); } + + if(type != DC_SIGCHAR_AGGREGATE) + f->alignment = f->size; + + /* aggr's field alignment is relative largest field size */ + if(ag->alignment < f->alignment) + ag->alignment = f->alignment; } diff -r ca28e9e3c644 -r ba70fb631bea dyncall/dyncall_aggregate.h --- a/dyncall/dyncall_aggregate.h Tue May 31 18:35:06 2022 +0200 +++ b/dyncall/dyncall_aggregate.h Tue May 31 19:29:34 2022 +0200 @@ -49,13 +49,13 @@ typedef struct DCfield_ { - DCsize offset, size, array_len; + DCsize offset, size, alignment, array_len; DCsigchar type; const DCaggr* sub_aggr; } DCfield; struct DCaggr_ { - DCsize size, n_fields; + DCsize size, n_fields, alignment; #if defined(DC_UNIX) && defined(DC__Arch_AMD64) DCuchar sysv_classes[DC_SYSV_MAX_NUM_CLASSES]; /* !code relies on this to be 64 bits! */ #endif diff -r ca28e9e3c644 -r ba70fb631bea dyncall/dyncall_aggregate_x64.c --- a/dyncall/dyncall_aggregate_x64.c Tue May 31 18:35:06 2022 +0200 +++ b/dyncall/dyncall_aggregate_x64.c Tue May 31 19:29:34 2022 +0200 @@ -69,6 +69,10 @@ if(offset >= (qword_offset + DC_ONE_8BYTE) || (offset + f->size * f->array_len) <= qword_offset) continue; + /* if field is unaligned, class is MEMORY */ + if(f->alignment && (offset % f->alignment) != 0) + return SYSVC_MEMORY; + DCuchar new_class = SYSVC_NONE; switch (f->type) { diff -r ca28e9e3c644 -r ba70fb631bea dyncall/dyncall_callvm_x64.c --- a/dyncall/dyncall_callvm_x64.c Tue May 31 18:35:06 2022 +0200 +++ b/dyncall/dyncall_callvm_x64.c Tue May 31 19:29:34 2022 +0200 @@ -168,8 +168,8 @@ DCCallVM_x64* self = (DCCallVM_x64*)in_self; if (!ag) { - /* non-trivial aggrs (C++) are passed via pointer (win and sysv callconv), - * copy has to be provided by user, as dyncall cannot do such copies*/ + /* non-trivial aggrs (C++) are passed via pointer (win and sysv callconv), + * copy has to be provided by user, as dyncall cannot do such copies*/ dc_callvm_argPointer_x64(in_self, (DCpointer)x); return; } @@ -254,7 +254,7 @@ #if defined(DC_UNIX) if (!ag || (ag->sysv_classes[0] == SYSVC_MEMORY)) { #else - if (!ag || ag->size > 8) { + if (!ag || ag->size > 8 || /*not a power of 2?*/(ag->size & (ag->size - 1))) #endif /* pass pointer to aggregate as hidden first argument */ self->mAggrReturnReg = 0; @@ -269,10 +269,8 @@ assert(self->mRegCount.i == 0 && self->mRegCount.f == 0 && "dc_callvm_begin_aggr_x64_win64_this should be called before any function arguments are declared"); - if (!ag || ag->size > 8) { - /* thiscall: this-ptr comes first, then pointer to aggregate as hidden (second) argument */ - self->mAggrReturnReg = 1; - } + /* thiscall: this-ptr comes first, then pointer to aggregate as hidden (second) argument */ + self->mAggrReturnReg = 1; } #endif diff -r ca28e9e3c644 -r ba70fb631bea dyncallback/dyncall_callback_x64.c --- a/dyncallback/dyncall_callback_x64.c Tue May 31 18:35:06 2022 +0200 +++ b/dyncallback/dyncall_callback_x64.c Tue May 31 19:29:34 2022 +0200 @@ -48,6 +48,7 @@ void dcbInitCallback2(DCCallback* pcb, const DCsigchar* signature, DCCallbackHandler* handler, void* userdata, DCaggr *const * aggrs) { const DCsigchar *ch = signature; + int mode = DC_CALL_C_DEFAULT; DCint num_aggrs = 0; pcb->handler = handler; @@ -55,6 +56,12 @@ pcb->aggrs = NULL; pcb->aggr_return_register = -2; /* default, = no aggr as ret value */ + if(*ch == DC_SIGCHAR_CC_PREFIX) + { + mode = dcGetModeFromCCSigChar(ch[1]); + ch += 2; + } + while(*ch) num_aggrs += (*(ch++) == DC_SIGCHAR_AGGREGATE); @@ -68,7 +75,9 @@ #if defined(DC_UNIX) if (!ag || (ag->sysv_classes[0] == SYSVC_MEMORY)) { #else - if (!ag || ag->size > 8) { + if (mode == DC_CALL_C_DEFAULT_THIS) { + pcb->aggr_return_register = 1; + } else if (!ag || ag->size > 8 || /*not a power of 2?*/(ag->size & (ag->size - 1))) { #endif /* we need to "return" this aggr as a hidden pointer (first arg) */ pcb->aggr_return_register = 0;