Commit 1a0f488c by Richard Henderson Committed by Richard Henderson

ffi64.c (struct register_args): Rename from stackLayout.

        * src/x86/ffi64.c (struct register_args): Rename from stackLayout.
        (enum x86_64_reg_class): Add X86_64_COMPLEX_X87_CLASS.
        (merge_classes): Check for it.
        (SSE_CLASS_P): New.
        (classify_argument): Pass byte_offset by value; perform all updates
        inside struct case.
        (examine_argument): Add classes argument; handle
        X86_64_COMPLEX_X87_CLASS.
        (ffi_prep_args): Merge into ...
        (ffi_call): ... here.  Share stack frame with ffi_call_unix64.
        (ffi_prep_cif_machdep): Setup cif->flags for proper structure return.
        (ffi_fill_return_value): Remove.
        (ffi_prep_closure): Remove dead assert.
        (ffi_closure_unix64_inner): Rename from ffi_closure_UNIX64_inner.
        Rewrite to use struct register_args instead of va_list.  Create
        flags for handling structure returns.
        * src/x86/unix64.S: Remove dead strings.
        (ffi_call_unix64): Rename from ffi_call_UNIX64.  Rewrite to share
        stack frame with ffi_call.  Handle structure returns properly.
        (float2sse, floatfloat2sse, double2sse): Remove.
        (sse2float, sse2double, sse2floatfloat): Remove.
        (ffi_closure_unix64): Rename from ffi_closure_UNIX64.  Rewrite
        to handle structure returns properly.

From-SVN: r92602
parent fa54a7a7
2004-12-25 Richard Henderson <rth@redhat.com>
* src/x86/ffi64.c (struct register_args): Rename from stackLayout.
(enum x86_64_reg_class): Add X86_64_COMPLEX_X87_CLASS.
(merge_classes): Check for it.
(SSE_CLASS_P): New.
(classify_argument): Pass byte_offset by value; perform all updates
inside struct case.
(examine_argument): Add classes argument; handle
X86_64_COMPLEX_X87_CLASS.
(ffi_prep_args): Merge into ...
(ffi_call): ... here. Share stack frame with ffi_call_unix64.
(ffi_prep_cif_machdep): Setup cif->flags for proper structure return.
(ffi_fill_return_value): Remove.
(ffi_prep_closure): Remove dead assert.
(ffi_closure_unix64_inner): Rename from ffi_closure_UNIX64_inner.
Rewrite to use struct register_args instead of va_list. Create
flags for handling structure returns.
* src/x86/unix64.S: Remove dead strings.
(ffi_call_unix64): Rename from ffi_call_UNIX64. Rewrite to share
stack frame with ffi_call. Handle structure returns properly.
(float2sse, floatfloat2sse, double2sse): Remove.
(sse2float, sse2double, sse2floatfloat): Remove.
(ffi_closure_unix64): Rename from ffi_closure_UNIX64. Rewrite
to handle structure returns properly.
2004-12-08 David Edelsohn <edelsohn@gnu.org> 2004-12-08 David Edelsohn <edelsohn@gnu.org>
* Makefile.am (AM_MAKEFLAGS): Remove duplicate LIBCFLAGS and * Makefile.am (AM_MAKEFLAGS): Remove duplicate LIBCFLAGS and
......
...@@ -29,22 +29,20 @@ ...@@ -29,22 +29,20 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
#ifdef __x86_64__ #ifdef __x86_64__
#define MAX_GPR_REGS 6 #define MAX_GPR_REGS 6
#define MAX_SSE_REGS 8 #define MAX_SSE_REGS 8
typedef struct
struct register_args
{ {
/* Registers for argument passing. */ /* Registers for argument passing. */
long gpr[MAX_GPR_REGS]; UINT64 gpr[MAX_GPR_REGS];
__int128_t sse[MAX_SSE_REGS]; __int128_t sse[MAX_SSE_REGS];
};
/* Stack space for arguments. */ extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
char argspace[0]; void *raddr, void (*fnaddr)());
} stackLayout;
/* All reference to register classes here is identical to the code in /* All reference to register classes here is identical to the code in
gcc/config/i386/i386.c. Do *not* change one without the other. */ gcc/config/i386/i386.c. Do *not* change one without the other. */
...@@ -55,8 +53,7 @@ typedef struct ...@@ -55,8 +53,7 @@ typedef struct
use SF or DFmode move instead of DImode to avoid reformating penalties. use SF or DFmode move instead of DImode to avoid reformating penalties.
Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
whenever possible (upper half does contain padding). whenever possible (upper half does contain padding). */
*/
enum x86_64_reg_class enum x86_64_reg_class
{ {
X86_64_NO_CLASS, X86_64_NO_CLASS,
...@@ -68,11 +65,14 @@ enum x86_64_reg_class ...@@ -68,11 +65,14 @@ enum x86_64_reg_class
X86_64_SSEUP_CLASS, X86_64_SSEUP_CLASS,
X86_64_X87_CLASS, X86_64_X87_CLASS,
X86_64_X87UP_CLASS, X86_64_X87UP_CLASS,
X86_64_COMPLEX_X87_CLASS,
X86_64_MEMORY_CLASS X86_64_MEMORY_CLASS
}; };
#define MAX_CLASSES 4 #define MAX_CLASSES 4
#define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS)
/* x86-64 register passing implementation. See x86-64 ABI for details. Goal /* x86-64 register passing implementation. See x86-64 ABI for details. Goal
of this code is to classify each 8bytes of incoming argument by the register of this code is to classify each 8bytes of incoming argument by the register
class and assign registers accordingly. */ class and assign registers accordingly. */
...@@ -106,9 +106,14 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) ...@@ -106,9 +106,14 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
|| class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
return X86_64_INTEGER_CLASS; return X86_64_INTEGER_CLASS;
/* Rule #5: If one of the classes is X87 or X87UP class, MEMORY is used. */ /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
if (class1 == X86_64_X87_CLASS || class1 == X86_64_X87UP_CLASS MEMORY is used. */
|| class2 == X86_64_X87_CLASS || class2 == X86_64_X87UP_CLASS) if (class1 == X86_64_X87_CLASS
|| class1 == X86_64_X87UP_CLASS
|| class1 == X86_64_COMPLEX_X87_CLASS
|| class2 == X86_64_X87_CLASS
|| class2 == X86_64_X87UP_CLASS
|| class2 == X86_64_COMPLEX_X87_CLASS)
return X86_64_MEMORY_CLASS; return X86_64_MEMORY_CLASS;
/* Rule #6: Otherwise class SSE is used. */ /* Rule #6: Otherwise class SSE is used. */
...@@ -125,11 +130,8 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) ...@@ -125,11 +130,8 @@ merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
*/ */
static int static int
classify_argument (ffi_type *type, enum x86_64_reg_class classes[], classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
int *byte_offset) size_t byte_offset)
{ {
/* First, align to the right place. */
*byte_offset = ALIGN(*byte_offset, type->alignment);
switch (type->type) switch (type->type)
{ {
case FFI_TYPE_UINT8: case FFI_TYPE_UINT8:
...@@ -141,13 +143,13 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], ...@@ -141,13 +143,13 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
case FFI_TYPE_UINT64: case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64: case FFI_TYPE_SINT64:
case FFI_TYPE_POINTER: case FFI_TYPE_POINTER:
if (((*byte_offset) % 8 + type->size) <= 4) if (byte_offset + type->size <= 4)
classes[0] = X86_64_INTEGERSI_CLASS; classes[0] = X86_64_INTEGERSI_CLASS;
else else
classes[0] = X86_64_INTEGER_CLASS; classes[0] = X86_64_INTEGER_CLASS;
return 1; return 1;
case FFI_TYPE_FLOAT: case FFI_TYPE_FLOAT:
if (((*byte_offset) % 8) == 0) if (byte_offset == 0)
classes[0] = X86_64_SSESF_CLASS; classes[0] = X86_64_SSESF_CLASS;
else else
classes[0] = X86_64_SSE_CLASS; classes[0] = X86_64_SSE_CLASS;
...@@ -175,22 +177,23 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], ...@@ -175,22 +177,23 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
classes[i] = X86_64_NO_CLASS; classes[i] = X86_64_NO_CLASS;
/* Merge the fields of structure. */ /* Merge the fields of structure. */
for (ptr=type->elements; (*ptr)!=NULL; ptr++) for (ptr = type->elements; *ptr != NULL; ptr++)
{ {
int num; int num;
num = classify_argument (*ptr, subclasses, byte_offset); byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
num = classify_argument (*ptr, subclasses, byte_offset % 8);
if (num == 0) if (num == 0)
return 0; return 0;
for (i = 0; i < num; i++) for (i = 0; i < num; i++)
{ {
int pos = *byte_offset / 8; int pos = byte_offset / 8;
classes[i + pos] = classes[i + pos] =
merge_classes (subclasses[i], classes[i + pos]); merge_classes (subclasses[i], classes[i + pos]);
} }
if ((*ptr)->type != FFI_TYPE_STRUCT) byte_offset += (*ptr)->size;
*byte_offset += (*ptr)->size;
} }
/* Final merger cleanup. */ /* Final merger cleanup. */
...@@ -222,359 +225,210 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[], ...@@ -222,359 +225,210 @@ classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
} }
/* Examine the argument and return set number of register required in each /* Examine the argument and return set number of register required in each
class. Return 0 iff parameter should be passed in memory. */ class. Return zero iff parameter should be passed in memory, otherwise
the number of registers. */
static int static int
examine_argument (ffi_type *type, int in_return, int *int_nregs,int *sse_nregs) examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
_Bool in_return, int *pngpr, int *pnsse)
{ {
enum x86_64_reg_class class[MAX_CLASSES]; int i, n, ngpr, nsse;
int offset = 0;
int n;
n = classify_argument (type, class, &offset);
n = classify_argument (type, classes, 0);
if (n == 0) if (n == 0)
return 0; return 0;
*int_nregs = 0; ngpr = nsse = 0;
*sse_nregs = 0; for (i = 0; i < n; ++i)
for (n--; n>=0; n--) switch (classes[i])
switch (class[n])
{ {
case X86_64_INTEGER_CLASS: case X86_64_INTEGER_CLASS:
case X86_64_INTEGERSI_CLASS: case X86_64_INTEGERSI_CLASS:
(*int_nregs)++; ngpr++;
break; break;
case X86_64_SSE_CLASS: case X86_64_SSE_CLASS:
case X86_64_SSESF_CLASS: case X86_64_SSESF_CLASS:
case X86_64_SSEDF_CLASS: case X86_64_SSEDF_CLASS:
(*sse_nregs)++; nsse++;
break; break;
case X86_64_NO_CLASS: case X86_64_NO_CLASS:
case X86_64_SSEUP_CLASS: case X86_64_SSEUP_CLASS:
break; break;
case X86_64_X87_CLASS: case X86_64_X87_CLASS:
case X86_64_X87UP_CLASS: case X86_64_X87UP_CLASS:
if (!in_return) case X86_64_COMPLEX_X87_CLASS:
return 0; return in_return != 0;
break;
default: default:
abort (); abort ();
} }
return 1;
}
/* Functions to load floats and double to an SSE register placeholder. */ *pngpr = ngpr;
extern void float2sse (float, __int128_t *); *pnsse = nsse;
extern void double2sse (double, __int128_t *);
extern void floatfloat2sse (void *, __int128_t *);
/* Functions to put the floats and doubles back. */ return n;
extern float sse2float (__int128_t *); }
extern double sse2double (__int128_t *);
extern void sse2floatfloat(__int128_t *, void *);
/*@-exportheader@*/ /* Perform machine dependent cif processing. */
void
ffi_prep_args (stackLayout *stack, extended_cif *ecif) ffi_status
/*@=exportheader@*/ ffi_prep_cif_machdep (ffi_cif *cif)
{ {
int gprcount, ssecount, i, g, s; int gprcount, ssecount, i, avn, n, ngpr, nsse, flags;
void **p_argv; enum x86_64_reg_class classes[MAX_CLASSES];
void *argp = &stack->argspace; size_t bytes;
ffi_type **p_arg;
/* First check if the return value should be passed in memory. If so,
pass the pointer as the first argument. */
gprcount = ssecount = 0; gprcount = ssecount = 0;
if (ecif->cif->rtype->type != FFI_TYPE_VOID
&& examine_argument (ecif->cif->rtype, 1, &g, &s) == 0)
stack->gpr[gprcount++] = (long) ecif->rvalue;
for (i=ecif->cif->nargs, p_arg=ecif->cif->arg_types, p_argv = ecif->avalue;
i!=0; i--, p_arg++, p_argv++)
{
int in_register = 0;
switch ((*p_arg)->type) flags = cif->rtype->type;
if (flags != FFI_TYPE_VOID)
{ {
case FFI_TYPE_SINT8: n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
case FFI_TYPE_SINT16: if (n == 0)
case FFI_TYPE_SINT32:
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_UINT32:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
if (gprcount < MAX_GPR_REGS)
{
stack->gpr[gprcount] = 0;
stack->gpr[gprcount++] = *(long long *)(*p_argv);
in_register = 1;
}
break;
case FFI_TYPE_FLOAT:
if (ssecount < MAX_SSE_REGS)
{
float2sse (*(float *)(*p_argv), &stack->sse[ssecount++]);
in_register = 1;
}
break;
case FFI_TYPE_DOUBLE:
if (ssecount < MAX_SSE_REGS)
{
double2sse (*(double *)(*p_argv), &stack->sse[ssecount++]);
in_register = 1;
}
break;
}
if (in_register)
continue;
/* Either all places in registers where filled, or this is a
type that potentially goes into a memory slot. */
if (examine_argument (*p_arg, 0, &g, &s) == 0
|| gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS)
{ {
/* Pass this argument in memory. */ /* The return value is passed in memory. A pointer to that
argp = (void *)ALIGN(argp, (*p_arg)->alignment); memory is the first argument. Allocate a register for it. */
/* Stack arguments are *always* at least 8 byte aligned. */ gprcount++;
argp = (void *)ALIGN(argp, 8); /* We don't have to do anything in asm for the return. */
memcpy (argp, *p_argv, (*p_arg)->size); flags = FFI_TYPE_VOID;
argp += (*p_arg)->size;
} }
else else if (flags == FFI_TYPE_STRUCT)
{ {
/* All easy cases are eliminated. Now fire the big guns. */ /* Mark which registers the result appears in. */
_Bool sse0 = SSE_CLASS_P (classes[0]);
enum x86_64_reg_class classes[MAX_CLASSES]; _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
int offset = 0, j, num; if (sse0 && !sse1)
void *a; flags |= 1 << 8;
else if (!sse0 && sse1)
num = classify_argument (*p_arg, classes, &offset); flags |= 1 << 9;
for (j=0, a=*p_argv; j<num; j++, a+=8) else if (sse0 && sse1)
{ flags |= 1 << 10;
switch (classes[j]) /* Mark the true size of the structure. */
{ flags |= cif->rtype->size << 11;
case X86_64_INTEGER_CLASS:
case X86_64_INTEGERSI_CLASS:
stack->gpr[gprcount++] = *(long long *)a;
break;
case X86_64_SSE_CLASS:
floatfloat2sse (a, &stack->sse[ssecount++]);
break;
case X86_64_SSESF_CLASS:
float2sse (*(float *)a, &stack->sse[ssecount++]);
break;
case X86_64_SSEDF_CLASS:
double2sse (*(double *)a, &stack->sse[ssecount++]);
break;
default:
abort();
} }
} }
} cif->flags = flags;
}
}
/* Perform machine dependent cif processing. */
ffi_status
ffi_prep_cif_machdep (ffi_cif *cif)
{
int gprcount, ssecount, i, g, s;
gprcount = ssecount = 0;
/* Reset the byte count. We handle this size estimation here. */
cif->bytes = 0;
/* If the return value should be passed in memory, pass the pointer
as the first argument. The actual memory isn't allocated here. */
if (cif->rtype->type != FFI_TYPE_VOID
&& examine_argument (cif->rtype, 1, &g, &s) == 0)
gprcount = 1;
/* Go over all arguments and determine the way they should be passed. /* Go over all arguments and determine the way they should be passed.
If it's in a register and there is space for it, let that be so. If If it's in a register and there is space for it, let that be so. If
not, add it's size to the stack byte count. */ not, add it's size to the stack byte count. */
for (i=0; i<cif->nargs; i++) for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
{ {
if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0 if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
|| gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS) || gprcount + ngpr > MAX_GPR_REGS
|| ssecount + nsse > MAX_SSE_REGS)
{ {
/* This is passed in memory. First align to the basic type. */ long align = cif->arg_types[i]->alignment;
cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment);
/* Stack arguments are *always* at least 8 byte aligned. */ if (align < 8)
cif->bytes = ALIGN(cif->bytes, 8); align = 8;
/* Now add the size of this argument. */ bytes = ALIGN(bytes, align);
cif->bytes += cif->arg_types[i]->size; bytes += cif->arg_types[i]->size;
} }
else else
{ {
gprcount += g; gprcount += ngpr;
ssecount += s; ssecount += nsse;
}
} }
/* Set the flag for the closures return. */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
case FFI_TYPE_SINT64:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_LONGDOUBLE:
cif->flags = (unsigned) cif->rtype->type;
break;
case FFI_TYPE_UINT64:
cif->flags = FFI_TYPE_SINT64;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
} }
cif->bytes = bytes;
return FFI_OK; return FFI_OK;
} }
typedef struct
{
long gpr[2];
__int128_t sse[2];
long double st0;
} return_value;
void void
ffi_fill_return_value (return_value *rv, extended_cif *ecif) ffi_call (ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue)
{ {
enum x86_64_reg_class classes[MAX_CLASSES]; enum x86_64_reg_class classes[MAX_CLASSES];
int i = 0, num; char *stack, *argp;
long *gpr = rv->gpr; ffi_type **arg_types;
__int128_t *sse = rv->sse; int gprcount, ssecount, ngpr, nsse, i, avn;
signed char sc; _Bool ret_in_memory;
signed short ss; struct register_args *reg_args;
/* This is needed because of the way x86-64 handles signed short /* Can't call 32-bit mode from 64-bit mode. */
integers. */ FFI_ASSERT (cif->abi == FFI_UNIX64);
switch (ecif->cif->rtype->type)
/* If the return value is a struct and we don't have a return value
address then we need to make one. Note the setting of flags to
VOID above in ffi_prep_cif_machdep. */
ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
&& cif->flags == FFI_TYPE_VOID);
if (rvalue == NULL && ret_in_memory)
rvalue = alloca (cif->rtype->size);
/* Allocate the space for the arguments, plus 4 words of temp space. */
stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
reg_args = (struct register_args *) stack;
argp = stack + sizeof (struct register_args);
gprcount = ssecount = 0;
/* If the return value is passed in memory, add the pointer as the
first integer argument. */
if (ret_in_memory)
reg_args->gpr[gprcount++] = (long) rvalue;
avn = cif->nargs;
arg_types = cif->arg_types;
for (i = 0; i < avn; ++i)
{ {
case FFI_TYPE_SINT8: size_t size = arg_types[i]->size;
sc = *(signed char *)gpr; int n;
*(long long *)ecif->rvalue = (long long)sc;
return;
case FFI_TYPE_SINT16:
ss = *(signed short *)gpr;
*(long long *)ecif->rvalue = (long long)ss;
return;
default:
/* Just continue. */
;
}
num = classify_argument (ecif->cif->rtype, classes, &i); n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
if (n == 0
|| gprcount + ngpr > MAX_GPR_REGS
|| ssecount + nsse > MAX_SSE_REGS)
{
long align = arg_types[i]->alignment;
if (num == 0) /* Stack arguments are *always* at least 8 byte aligned. */
/* Return in memory. */ if (align < 8)
ecif->rvalue = (void *) rv->gpr[0]; align = 8;
else if (num == 2 && classes[0] == X86_64_X87_CLASS &&
classes[1] == X86_64_X87UP_CLASS) /* Pass this argument in memory. */
/* This is a long double (this is easiest to handle this way instead argp = (void *) ALIGN (argp, align);
of an eightbyte at a time as in the loop below. */ memcpy (argp, avalue[i], size);
*((long double *)ecif->rvalue) = rv->st0; argp += size;
}
else else
{ {
void *a; /* The argument is passed entirely in registers. */
char *a = (char *) avalue[i];
int j;
for (i=0, a=ecif->rvalue; i<num; i++, a+=8) for (j = 0; j < n; j++, a += 8, size -= 8)
{ {
switch (classes[i]) switch (classes[j])
{ {
case X86_64_INTEGER_CLASS: case X86_64_INTEGER_CLASS:
case X86_64_INTEGERSI_CLASS: case X86_64_INTEGERSI_CLASS:
*(long long *)a = *gpr; reg_args->gpr[gprcount] = 0;
gpr++; memcpy (&reg_args->gpr[gprcount], a, size < 8 ? size : 8);
gprcount++;
break; break;
case X86_64_SSE_CLASS: case X86_64_SSE_CLASS:
sse2floatfloat (sse++, a); case X86_64_SSEDF_CLASS:
reg_args->sse[ssecount++] = *(UINT64 *) a;
break; break;
case X86_64_SSESF_CLASS: case X86_64_SSESF_CLASS:
*(float *)a = sse2float (sse++); reg_args->sse[ssecount++] = *(UINT32 *) a;
break;
case X86_64_SSEDF_CLASS:
*(double *)a = sse2double (sse++);
break; break;
default: default:
abort(); abort();
} }
} }
} }
}
/*@-declundef@*/
/*@-exportheader@*/
extern void ffi_call_UNIX64(void (*)(stackLayout *, extended_cif *),
void (*) (return_value *, extended_cif *),
/*@out@*/ extended_cif *,
unsigned, /*@out@*/ unsigned *, void (*fn)());
/*@=declundef@*/
/*@=exportheader@*/
void ffi_call(/*@dependent@*/ ffi_cif *cif,
void (*fn)(),
/*@out@*/ void *rvalue,
/*@dependent@*/ void **avalue)
{
extended_cif ecif;
int dummy;
ecif.cif = cif;
ecif.avalue = avalue;
/* If the return value is a struct and we don't have a return */
/* value address then we need to make one */
if ((rvalue == NULL) &&
(examine_argument (cif->rtype, 1, &dummy, &dummy) == 0))
{
/*@-sysunrecog@*/
ecif.rvalue = alloca(cif->rtype->size);
/*@=sysunrecog@*/
} }
else
ecif.rvalue = rvalue;
/* Stack must always be 16byte aligned. Make it so. */
cif->bytes = ALIGN(cif->bytes, 16);
switch (cif->abi)
{
case FFI_SYSV:
/* Calling 32bit code from 64bit is not possible */
FFI_ASSERT(0);
break;
case FFI_UNIX64: ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
/*@-usedef@*/ cif->flags, rvalue, fn);
ffi_call_UNIX64 (ffi_prep_args, ffi_fill_return_value, &ecif,
cif->bytes, ecif.rvalue, fn);
/*@=usedef@*/
break;
default:
FFI_ASSERT(0);
break;
}
} }
extern void ffi_closure_UNIX64(void);
extern void ffi_closure_unix64(void);
ffi_status ffi_status
ffi_prep_closure (ffi_closure* closure, ffi_prep_closure (ffi_closure* closure,
...@@ -584,14 +438,12 @@ ffi_prep_closure (ffi_closure* closure, ...@@ -584,14 +438,12 @@ ffi_prep_closure (ffi_closure* closure,
{ {
volatile unsigned short *tramp; volatile unsigned short *tramp;
/* FFI_ASSERT (cif->abi == FFI_OSF); */
tramp = (volatile unsigned short *) &closure->tramp[0]; tramp = (volatile unsigned short *) &closure->tramp[0];
tramp[0] = 0xbb49; /* mov <code>, %r11 */ tramp[0] = 0xbb49; /* mov <code>, %r11 */
tramp[5] = 0xba49; /* mov <data>, %r10 */ tramp[5] = 0xba49; /* mov <data>, %r10 */
tramp[10] = 0xff49; /* jmp *%r11 */ tramp[10] = 0xff49; /* jmp *%r11 */
tramp[11] = 0x00e3; tramp[11] = 0x00e3;
*(void * volatile *) &tramp[1] = ffi_closure_UNIX64; *(void * volatile *) &tramp[1] = ffi_closure_unix64;
*(void * volatile *) &tramp[6] = closure; *(void * volatile *) &tramp[6] = closure;
closure->cif = cif; closure->cif = cif;
...@@ -602,107 +454,109 @@ ffi_prep_closure (ffi_closure* closure, ...@@ -602,107 +454,109 @@ ffi_prep_closure (ffi_closure* closure,
} }
int int
ffi_closure_UNIX64_inner(ffi_closure *closure, va_list l, void *rp) ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
struct register_args *reg_args, char *argp)
{ {
ffi_cif *cif; ffi_cif *cif;
void **avalue; void **avalue;
ffi_type **arg_types; ffi_type **arg_types;
long i, avn, argn; long i, avn;
int gprcount, ssecount, ngpr, nsse;
int ret;
cif = closure->cif; cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *)); avalue = alloca(cif->nargs * sizeof(void *));
gprcount = ssecount = 0;
argn = 0; ret = cif->rtype->type;
if (ret != FFI_TYPE_VOID)
i = 0;
avn = cif->nargs;
arg_types = cif->arg_types;
/* Grab the addresses of the arguments from the stack frame. */
while (i < avn)
{
switch (arg_types[i]->type)
{
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT64:
case FFI_TYPE_UINT64:
case FFI_TYPE_POINTER:
{ {
if (l->gp_offset > 48-8) enum x86_64_reg_class classes[MAX_CLASSES];
int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
if (n == 0)
{ {
avalue[i] = l->overflow_arg_area; /* The return value goes in memory. Arrange for the closure
l->overflow_arg_area = (char *)l->overflow_arg_area + 8; return value to go directly back to the original caller. */
rvalue = (void *) reg_args->gpr[gprcount++];
/* We don't have to do anything in asm for the return. */
ret = FFI_TYPE_VOID;
} }
else else if (ret == FFI_TYPE_STRUCT && n == 2)
{ {
avalue[i] = (char *)l->reg_save_area + l->gp_offset; /* Mark which register the second word of the structure goes in. */
l->gp_offset += 8; _Bool sse0 = SSE_CLASS_P (classes[0]);
_Bool sse1 = SSE_CLASS_P (classes[1]);
if (!sse0 && sse1)
ret |= 1 << 8;
else if (sse0 && !sse1)
ret |= 1 << 9;
} }
} }
break;
case FFI_TYPE_STRUCT: avn = cif->nargs;
/* FIXME */ arg_types = cif->arg_types;
FFI_ASSERT(0);
break;
case FFI_TYPE_DOUBLE: for (i = 0; i < avn; ++i)
{
if (l->fp_offset > 176-16)
{ {
avalue[i] = l->overflow_arg_area; enum x86_64_reg_class classes[MAX_CLASSES];
l->overflow_arg_area = (char *)l->overflow_arg_area + 8; int n;
}
else n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
if (n == 0
|| gprcount + ngpr > MAX_GPR_REGS
|| ssecount + nsse > MAX_SSE_REGS)
{ {
avalue[i] = (char *)l->reg_save_area + l->fp_offset; long align = arg_types[i]->alignment;
l->fp_offset += 16;
}
}
#if DEBUG_FFI
fprintf (stderr, "double arg %d = %g\n", i, *(double *)avalue[i]);
#endif
break;
case FFI_TYPE_FLOAT: /* Stack arguments are *always* at least 8 byte aligned. */
if (align < 8)
align = 8;
/* Pass this argument in memory. */
argp = (void *) ALIGN (argp, align);
avalue[i] = argp;
argp += arg_types[i]->size;
}
/* If the argument is in a single register, or two consecutive
registers, then we can use that address directly. */
else if (n == 1
|| (n == 2
&& SSE_CLASS_P (classes[0]) == SSE_CLASS_P (classes[1])))
{ {
if (l->fp_offset > 176-16) /* The argument is in a single register. */
if (SSE_CLASS_P (classes[0]))
{ {
avalue[i] = l->overflow_arg_area; avalue[i] = &reg_args->sse[ssecount];
l->overflow_arg_area = (char *)l->overflow_arg_area + 8; ssecount += n;
} }
else else
{ {
avalue[i] = (char *)l->reg_save_area + l->fp_offset; avalue[i] = &reg_args->gpr[gprcount];
l->fp_offset += 16; gprcount += n;
} }
} }
#if DEBUG_FFI /* Otherwise, allocate space to make them consecutive. */
fprintf (stderr, "float arg %d = %g\n", i, *(float *)avalue[i]); else
#endif {
break; char *a = alloca (16);
int j;
default: avalue[i] = a;
FFI_ASSERT(0); for (j = 0; j < n; j++, a += 8)
{
if (SSE_CLASS_P (classes[j]))
memcpy (a, &reg_args->sse[ssecount++], 8);
else
memcpy (a, &reg_args->gpr[gprcount++], 8);
}
} }
argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
i++;
} }
/* Invoke the closure. */ /* Invoke the closure. */
(closure->fun) (cif, rp, avalue, closure->user_data); closure->fun (cif, rvalue, avalue, closure->user_data);
/* FIXME: Structs not supported. */ /* Tell assembly how to perform return type promotions. */
FFI_ASSERT(cif->rtype->type != FFI_TYPE_STRUCT); return ret;
/* Tell ffi_closure_UNIX64 how to perform return type promotions. */
return cif->rtype->type;
} }
#endif /* ifndef __x86_64__ */
#endif /* __x86_64__ */
...@@ -28,275 +28,347 @@ ...@@ -28,275 +28,347 @@
#include <fficonfig.h> #include <fficonfig.h>
#include <ffi.h> #include <ffi.h>
.section .rodata
.LC0:
.string "asm in progress %lld\n"
.LC1:
.string "asm in progress\n"
.text .text
/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
void *raddr, void (*fnaddr)());
Bit o trickiness here -- ARGS+BYTES is the base of the stack frame
for this function. This has been allocated by ffi_call. We also
deallocate some of the stack that has been alloca'd. */
.align 2 .align 2
.globl ffi_call_UNIX64 .globl ffi_call_unix64
.type ffi_call_UNIX64,@function .type ffi_call_unix64,@function
ffi_call_UNIX64: ffi_call_unix64:
.LFB1: .LUW0:
pushq %rbp movq (%rsp), %r10 /* Load return address. */
.LCFI0: leaq (%rdi, %rsi), %rax /* Find local stack base. */
movq %rsp, %rbp movq %rdx, (%rax) /* Save flags. */
.LCFI1: movq %rcx, 8(%rax) /* Save raddr. */
/* Save all arguments */ movq %rbp, 16(%rax) /* Save old frame pointer. */
subq $48, %rsp movq %r10, 24(%rax) /* Relocate return address. */
.LCFI2: movq %rax, %rbp /* Finalize local stack frame. */
movq %rdi, -8(%rbp) /* ffi_prep_args */ .LUW1:
movq %rsi, -16(%rbp) /* ffi_fill_return_value */ movq %rdi, %r10 /* Save a copy of the register area. */
movq %rdx, -24(%rbp) /* ecif */ movq %r8, %r11 /* Save a copy of the target fn. */
movq %rcx, -32(%rbp) /* cif->bytes */
movq %r8, -40(%rbp) /* ecif.rvalue */ /* Load up all argument registers. */
movq %r9, -48(%rbp) /* fn */ movq (%r10), %rdi
movq 8(%r10), %rsi
/* Make room for all of the new args and the register args */ movq 16(%r10), %rdx
addl $176, %ecx movq 24(%r10), %rcx
.LCFI3: movq 32(%r10), %r8
subq %rcx, %rsp movq 40(%r10), %r9
.LCFI4: movdqa 48(%r10), %xmm0
/* Setup the call to ffi_prep_args. */ movdqa 64(%r10), %xmm1
movq %rdi, %rax /* &ffi_prep_args */ movdqa 80(%r10), %xmm2
movq %rsp, %rdi /* stackLayout */ movdqa 96(%r10), %xmm3
movq %rdx, %rsi /* ecif */ movdqa 112(%r10), %xmm4
call *%rax /* ffi_prep_args(stackLayout, ecif);*/ movdqa 128(%r10), %xmm5
movdqa 144(%r10), %xmm6
/* ffi_prep_args have put all the register contents into the */ movdqa 160(%r10), %xmm7
/* stackLayout struct. Now put the register values in place. */
movq (%rsp), %rdi /* Deallocate the reg arg area. */
movq 8(%rsp), %rsi leaq 176(%r10), %rsp
movq 16(%rsp), %rdx
movq 24(%rsp), %rcx
movq 32(%rsp), %r8
movq 40(%rsp), %r9
movaps 48(%rsp), %xmm0
movaps 64(%rsp), %xmm1
movaps 80(%rsp), %xmm2
movaps 96(%rsp), %xmm3
movaps 112(%rsp), %xmm4
movaps 128(%rsp), %xmm5
movaps 144(%rsp), %xmm6
movaps 160(%rsp), %xmm7
/* Remove space for stackLayout so stack arguments are placed
correctly for the call. */
.LCFI5:
addq $176, %rsp
.LCFI6:
/* Call the user function. */ /* Call the user function. */
call *-48(%rbp) call *%r11
/* Make stack space for the return_value struct. */
subq $64, %rsp
/* Fill in all potential return values to this struct. */
movq %rax, (%rsp)
movq %rdx, 8(%rsp)
movaps %xmm0, 16(%rsp)
movaps %xmm1, 32(%rsp)
fstpt 48(%rsp)
/* Now call ffi_fill_return_value. */
movq %rsp, %rdi /* struct return_value */
movq -24(%rbp), %rsi /* ecif */
movq -16(%rbp), %rax /* &ffi_fill_return_value */
call *%rax /* call it */
/* And the work is done. */
leave
ret
.LFE1:
.ffi_call_UNIX64_end:
.size ffi_call_UNIX64,.ffi_call_UNIX64_end-ffi_call_UNIX64
.text /* Deallocate stack arg area; local stack frame in redzone. */
leaq 24(%rbp), %rsp
movq 0(%rbp), %rcx /* Reload flags. */
movq 8(%rbp), %rdi /* Reload raddr. */
movq 16(%rbp), %rbp /* Reload old frame pointer. */
.LUW2:
/* The first byte of the flags contains the FFI_TYPE. */
movzbl %cl, %r10d
leaq .Lstore_table(%rip), %r11
movslq (%r11, %r10, 4), %r10
addq %r11, %r10
jmp *%r10
.section .rodata
.Lstore_table:
.long .Lst_void-.Lstore_table /* FFI_TYPE_VOID */
.long .Lst_sint32-.Lstore_table /* FFI_TYPE_INT */
.long .Lst_float-.Lstore_table /* FFI_TYPE_FLOAT */
.long .Lst_double-.Lstore_table /* FFI_TYPE_DOUBLE */
.long .Lst_ldouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */
.long .Lst_uint8-.Lstore_table /* FFI_TYPE_UINT8 */
.long .Lst_sint8-.Lstore_table /* FFI_TYPE_SINT8 */
.long .Lst_uint16-.Lstore_table /* FFI_TYPE_UINT16 */
.long .Lst_sint16-.Lstore_table /* FFI_TYPE_SINT16 */
.long .Lst_uint32-.Lstore_table /* FFI_TYPE_UINT32 */
.long .Lst_sint32-.Lstore_table /* FFI_TYPE_SINT32 */
.long .Lst_int64-.Lstore_table /* FFI_TYPE_UINT64 */
.long .Lst_int64-.Lstore_table /* FFI_TYPE_SINT64 */
.long .Lst_struct-.Lstore_table /* FFI_TYPE_STRUCT */
.long .Lst_int64-.Lstore_table /* FFI_TYPE_POINTER */
.text
.align 2 .align 2
.globl float2sse .Lst_void:
.type float2sse,@function
float2sse:
/* Save the contents of this sse-float in a pointer. */
movaps %xmm0, (%rdi)
ret ret
.align 2
.Lst_uint8:
movzbq %al, %rax
movq %rax, (%rdi)
ret
.align 2 .align 2
.globl floatfloat2sse .Lst_sint8:
.type floatfloat2sse,@function movsbq %al, %rax
floatfloat2sse: movq %rax, (%rdi)
/* Save the contents of these two sse-floats in a pointer. */
movq (%rdi), %xmm0
movaps %xmm0, (%rsi)
ret ret
.align 2 .align 2
.globl double2sse .Lst_uint16:
.type double2sse,@function movzwq %ax, %rax
double2sse: movq %rax, (%rdi)
/* Save the contents of this sse-double in a pointer. */ .align 2
movaps %xmm0, (%rdi) .Lst_sint16:
movswq %ax, %rax
movq %rax, (%rdi)
ret
.align 2
.Lst_uint32:
movl %eax, %eax
movq %rax, (%rdi)
.align 2
.Lst_sint32:
cltq
movq %rax, (%rdi)
ret ret
.align 2 .align 2
.globl sse2float .Lst_int64:
.type sse2float,@function movq %rax, (%rdi)
sse2float:
/* Save the contents of this sse-float in a pointer. */
movaps (%rdi), %xmm0
ret ret
.align 2 .align 2
.globl sse2double .Lst_float:
.type sse2double,@function movss %xmm0, (%rdi)
sse2double: ret
/* Save the contents of this pointer in a sse-double. */ .align 2
movaps (%rdi), %xmm0 .Lst_double:
movsd %xmm0, (%rdi)
ret
.Lst_ldouble:
fstpt (%rdi)
ret ret
.align 2 .align 2
.globl sse2floatfloat .Lst_struct:
.type sse2floatfloat,@function leaq -20(%rsp), %rsi /* Scratch area in redzone. */
sse2floatfloat:
/* Save the contents of this pointer in two sse-floats. */ /* We have to locate the values now, and since we don't want to
movaps (%rdi), %xmm0 write too much data into the user's return value, we spill the
movq %xmm0, (%rsi) value to a 16 byte scratch area first. Bits 8, 9, and 10
control where the values are located. Only one of the three
bits will be set; see ffi_prep_cif_machdep for the pattern. */
movd %xmm0, %r10
movd %xmm1, %r11
testl $0x100, %ecx
cmovnz %rax, %rdx
cmovnz %r10, %rax
testl $0x200, %ecx
cmovnz %r10, %rdx
testl $0x400, %ecx
cmovnz %r10, %rax
cmovnz %r11, %rdx
movq %rax, (%rsi)
movq %rdx, 8(%rsi)
/* Bits 11-31 contain the true size of the structure. Copy from
the scratch area to the true destination. */
shrl $11, %ecx
rep movsb
ret ret
.LUW3:
.size ffi_call_unix64,.-ffi_call_unix64
.align 2 .align 2
.globl ffi_closure_UNIX64 .globl ffi_closure_unix64
.type ffi_closure_UNIX64,@function .type ffi_closure_unix64,@function
ffi_closure_UNIX64: ffi_closure_unix64:
.LFB2: .LUW4:
pushq %rbp subq $200, %rsp
.LCFI10: .LUW5:
movq %rsp, %rbp
.LCFI11: movq %rdi, (%rsp)
subq $240, %rsp movq %rsi, 8(%rsp)
.LCFI12: movq %rdx, 16(%rsp)
movq %rdi, -176(%rbp) movq %rcx, 24(%rsp)
movq %rsi, -168(%rbp) movq %r8, 32(%rsp)
movq %rdx, -160(%rbp) movq %r9, 40(%rsp)
movq %rcx, -152(%rbp) movdqa %xmm0, 48(%rsp)
movq %r8, -144(%rbp) movdqa %xmm1, 64(%rsp)
movq %r9, -136(%rbp) movdqa %xmm2, 80(%rsp)
/* FIXME: We can avoid all this stashing of XMM registers by movdqa %xmm3, 96(%rsp)
(in ffi_prep_closure) computing the number of movdqa %xmm4, 112(%rsp)
floating-point args and moving it into %rax before calling movdqa %xmm5, 128(%rsp)
this function. Once this is done, uncomment the next few movdqa %xmm6, 144(%rsp)
lines and only the essential XMM registers will be written movdqa %xmm7, 160(%rsp)
to memory. This is a significant saving. */
/* movzbl %al, %eax */
/* movq %rax, %rdx */
/* leaq 0(,%rdx,4), %rax */
/* leaq 2f(%rip), %rdx */
/* subq %rax, %rdx */
leaq -1(%rbp), %rax
/* jmp *%rdx */
movaps %xmm7, -15(%rax)
movaps %xmm6, -31(%rax)
movaps %xmm5, -47(%rax)
movaps %xmm4, -63(%rax)
movaps %xmm3, -79(%rax)
movaps %xmm2, -95(%rax)
movaps %xmm1, -111(%rax)
movaps %xmm0, -127(%rax)
2:
movl %edi, -180(%rbp)
movl $0, -224(%rbp)
movl $48, -220(%rbp)
leaq 16(%rbp), %rax
movq %rax, -216(%rbp)
leaq -176(%rbp), %rdx
movq %rdx, -208(%rbp)
leaq -224(%rbp), %rsi
movq %r10, %rdi movq %r10, %rdi
leaq 176(%rsp), %rsi
movq %rsp, %rdx movq %rsp, %rdx
call ffi_closure_UNIX64_inner@PLT leaq 208(%rsp), %rcx
call ffi_closure_unix64_inner@PLT
cmpl $FFI_TYPE_FLOAT, %eax
je 1f /* Deallocate stack frame early; return value is now in redzone. */
cmpl $FFI_TYPE_DOUBLE, %eax addq $200, %rsp
je 2f .LUW6:
cmpl $FFI_TYPE_LONGDOUBLE, %eax
je 3f /* The first byte of the return value contains the FFI_TYPE. */
cmpl $FFI_TYPE_STRUCT, %eax movzbl %al, %r10d
je 4f leaq .Lload_table(%rip), %r11
popq %rax movslq (%r11, %r10, 4), %r10
leave addq %r11, %r10
jmp *%r10
.section .rodata
.Lload_table:
.long .Lld_void-.Lload_table /* FFI_TYPE_VOID */
.long .Lld_int32-.Lload_table /* FFI_TYPE_INT */
.long .Lld_float-.Lload_table /* FFI_TYPE_FLOAT */
.long .Lld_double-.Lload_table /* FFI_TYPE_DOUBLE */
.long .Lld_ldouble-.Lload_table /* FFI_TYPE_LONGDOUBLE */
.long .Lld_int8-.Lload_table /* FFI_TYPE_UINT8 */
.long .Lld_int8-.Lload_table /* FFI_TYPE_SINT8 */
.long .Lld_int16-.Lload_table /* FFI_TYPE_UINT16 */
.long .Lld_int16-.Lload_table /* FFI_TYPE_SINT16 */
.long .Lld_int32-.Lload_table /* FFI_TYPE_UINT32 */
.long .Lld_int32-.Lload_table /* FFI_TYPE_SINT32 */
.long .Lld_int64-.Lload_table /* FFI_TYPE_UINT64 */
.long .Lld_int64-.Lload_table /* FFI_TYPE_SINT64 */
.long .Lld_struct-.Lload_table /* FFI_TYPE_STRUCT */
.long .Lld_int64-.Lload_table /* FFI_TYPE_POINTER */
.text
.align 2
.Lld_void:
ret
.align 2
.Lld_int8:
movzbl -24(%rsp), %eax
ret
.align 2
.Lld_int16:
movzwl -24(%rsp), %eax
ret
.align 2
.Lld_int32:
movl -24(%rsp), %eax
ret
.align 2
.Lld_int64:
movq -24(%rsp), %rax
ret
.align 2
.Lld_float:
movss -24(%rsp), %xmm0
ret
.align 2
.Lld_double:
movsd -24(%rsp), %xmm0
ret ret
1: .align 2
2: .Lld_ldouble:
3: fldt -24(%rsp)
movaps -240(%rbp), %xmm0
leave
ret ret
4:
leave .align 2
.Lld_struct:
/* There are four possibilities here, %rax/%rdx, %xmm0/%rax,
%rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading
both rdx and xmm1 with the second word. For the remaining,
bit 8 set means xmm0 gets the second word, and bit 9 means
that rax gets the second word. */
movq -24(%rsp), %rcx
movq -16(%rsp), %rdx
movq -16(%rsp), %xmm1
testl $0x100, %eax
cmovnz %rdx, %rcx
movd %rcx, %xmm0
testl $0x200, %eax
movq -24(%rsp), %rax
cmovnz %rdx, %rax
ret ret
.LFE2: .LUW7:
.size ffi_closure_unix64,.-ffi_closure_unix64
.section .eh_frame,EH_FRAME_FLAGS,@progbits .section .eh_frame,"a",@progbits
.Lframe0: .Lframe1:
.long .LECIE1-.LSCIE1 .long .LECIE1-.LSCIE1 /* CIE Length */
.LSCIE1: .LSCIE1:
.long 0x0 .long 0 /* CIE Identifier Tag */
.byte 0x1 .byte 1 /* CIE Version */
.string "zR" .ascii "zR\0" /* CIE Augmentation */
.uleb128 0x1 .uleb128 1 /* CIE Code Alignment Factor */
.sleb128 -8 .sleb128 -8 /* CIE Data Alignment Factor */
.byte 0x10 .byte 0x10 /* CIE RA Column */
.uleb128 0x1 .uleb128 1 /* Augmentation size */
.byte 0x1b .byte 0x1b /* FDE Encoding (pcrel sdata4) */
.byte 0xc .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
.uleb128 0x7 .uleb128 7
.uleb128 0x8 .uleb128 8
.byte 0x90 .byte 0x80+16 /* DW_CFA_offset, %rip offset 1*-8 */
.uleb128 0x1 .uleb128 1
.align 8 .align 8
.LECIE1: .LECIE1:
.LSFDE1: .LSFDE1:
.long .LEFDE1-.LASFDE1 .long .LEFDE1-.LASFDE1 /* FDE Length */
.LASFDE1: .LASFDE1:
.long .LASFDE1-.Lframe0 .long .LASFDE1-.Lframe1 /* FDE CIE offset */
.long .LUW0-. /* FDE initial location */
.long .LFB1-. .long .LUW3-.LUW0 /* FDE address range */
.long .LFE1-.LFB1 .uleb128 0x0 /* Augmentation size */
.uleb128 0x0
.byte 0x4 # DW_CFA_advance_loc4 .byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI0-.LFB1 .long .LUW1-.LUW0
.byte 0xe # DW_CFA_def_cfa_offset
.uleb128 0x10 /* New stack frame based off rbp. This is a itty bit of unwind
.byte 0x86 # DW_CFA_offset: r6 at cfa-16 trickery in that the CFA *has* changed. There is no easy way
.uleb128 0x2 to describe it correctly on entry to the function. Fortunately,
.byte 0x4 # DW_CFA_advance_loc4 it doesn't matter too much since at all points we can correctly
.long .LCFI1-.LCFI0 unwind back to ffi_call. Note that the location to which we
.byte 0x86 # DW_CFA_offset: r6 at cfa-16 moved the return address is (the new) CFA-8, so from the
.uleb128 0x2 perspective of the unwind info, it hasn't moved. */
.byte 0xd # DW_CFA_def_cfa_reg: r6 .byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */
.uleb128 0x6 .uleb128 6
.uleb128 32
.byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */
.uleb128 2
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LUW2-.LUW3
.byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */
.uleb128 7
.uleb128 8
.byte 0xc0+6 /* DW_CFA_restore, %rbp */
.align 8 .align 8
.LEFDE1: .LEFDE1:
.LSFDE3: .LSFDE3:
.long .LEFDE3-.LASFDE3 # FDE Length .long .LEFDE3-.LASFDE3 /* FDE Length */
.LASFDE3: .LASFDE3:
.long .LASFDE3-.Lframe0 # FDE CIE offset .long .LASFDE3-.Lframe1 /* FDE CIE offset */
.long .LUW4-. /* FDE initial location */
.long .LFB2-. # FDE initial location .long .LUW7-.LUW4 /* FDE address range */
.long .LFE2-.LFB2 # FDE address range .uleb128 0x0 /* Augmentation size */
.uleb128 0x0 # Augmentation size .byte 0x4 /* DW_CFA_advance_loc4 */
.byte 0x4 # DW_CFA_advance_loc4 .long .LUW5-.LUW4
.long .LCFI10-.LFB2 .byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0xe # DW_CFA_def_cfa_offset .uleb128 208
.uleb128 0x10 .byte 0x4 /* DW_CFA_advance_loc4 */
.byte 0x86 # DW_CFA_offset, column 0x6 .long .LUW6-.LUW5
.uleb128 0x2 .byte 0xe /* DW_CFA_def_cfa_offset */
.byte 0x4 # DW_CFA_advance_loc4 .uleb128 8
.long .LCFI11-.LCFI10
.byte 0xd # DW_CFA_def_cfa_register
.uleb128 0x6
.align 8 .align 8
.LEFDE3: .LEFDE3:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment