changeset 546:ba70fb631bea

x64: * support for non-standard aggr-by-value packing (#pragma pack, etc.) * callbacks: handling callconv prefixes in signature
author Tassilo Philipp
date Tue, 31 May 2022 19:29:34 +0200
parents ca28e9e3c644
children 917d5d213815
files dyncall/dyncall_aggregate.c dyncall/dyncall_aggregate.h dyncall/dyncall_aggregate_x64.c dyncall/dyncall_callvm_x64.c dyncallback/dyncall_callback_x64.c
diffstat 5 files changed, 30 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- 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;
 }
 
 
--- 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
--- 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) {
--- 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
 
--- 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;