📄 ffi64.c
字号:
num = classify_argument (*p_arg, classes, &offset); for (j=0, a=*p_argv; j<num; j++, a+=8) { switch (classes[j]) { 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(); } } } }}/* Perform machine dependent cif processing. */ffi_statusffi_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. 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. */ for (i=0; i<cif->nargs; i++) { if (examine_argument (cif->arg_types[i], 0, &g, &s) == 0 || gprcount + g > MAX_GPR_REGS || ssecount + s > MAX_SSE_REGS) { /* This is passed in memory. First align to the basic type. */ cif->bytes = ALIGN(cif->bytes, cif->arg_types[i]->alignment); /* Stack arguments are *always* at least 8 byte aligned. */ cif->bytes = ALIGN(cif->bytes, 8); /* Now add the size of this argument. */ cif->bytes += cif->arg_types[i]->size; } else { gprcount += g; ssecount += s; } } /* 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; } return FFI_OK;}typedef struct{ long gpr[2]; __int128_t sse[2]; long double st0;} return_value;voidffi_fill_return_value (return_value *rv, extended_cif *ecif){ enum x86_64_reg_class classes[MAX_CLASSES]; int i = 0, num; long *gpr = rv->gpr; __int128_t *sse = rv->sse; signed char sc; signed short ss; /* This is needed because of the way x86-64 handles signed short integers. */ switch (ecif->cif->rtype->type) { case FFI_TYPE_SINT8: sc = *(signed char *)gpr; *(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); if (num == 0) /* Return in memory. */ ecif->rvalue = (void *) rv->gpr[0]; else if (num == 2 && classes[0] == X86_64_X87_CLASS && classes[1] == X86_64_X87UP_CLASS) /* This is a long double (this is easiest to handle this way instead of an eightbyte at a time as in the loop below. */ *((long double *)ecif->rvalue) = rv->st0; else { void *a; for (i=0, a=ecif->rvalue; i<num; i++, a+=8) { switch (classes[i]) { case X86_64_INTEGER_CLASS: case X86_64_INTEGERSI_CLASS: *(long long *)a = *gpr; gpr++; break; case X86_64_SSE_CLASS: sse2floatfloat (sse++, a); break; case X86_64_SSESF_CLASS: *(float *)a = sse2float (sse++); break; case X86_64_SSEDF_CLASS: *(double *)a = sse2double (sse++); break; default: 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: /*@-usedef@*/ 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);ffi_statusffi_prep_closure (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data){ volatile unsigned short *tramp; /* FFI_ASSERT (cif->abi == FFI_OSF); */ tramp = (volatile unsigned short *) &closure->tramp[0]; tramp[0] = 0xbb49; /* mov <code>, %r11 */ tramp[5] = 0xba49; /* mov <data>, %r10 */ tramp[10] = 0xff49; /* jmp *%r11 */ tramp[11] = 0x00e3; *(void * volatile *) &tramp[1] = ffi_closure_UNIX64; *(void * volatile *) &tramp[6] = closure; closure->cif = cif; closure->fun = fun; closure->user_data = user_data; return FFI_OK;}intffi_closure_UNIX64_inner(ffi_closure *closure, va_list l, void *rp){ ffi_cif *cif; void **avalue; ffi_type **arg_types; long i, avn, argn; cif = closure->cif; avalue = alloca(cif->nargs * sizeof(void *)); argn = 0; 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) { avalue[i] = l->overflow_arg_area; l->overflow_arg_area = (char *)l->overflow_arg_area + 8; } else { avalue[i] = (char *)l->reg_save_area + l->gp_offset; l->gp_offset += 8; } } break; case FFI_TYPE_STRUCT: /* FIXME */ FFI_ASSERT(0); break; case FFI_TYPE_DOUBLE: { if (l->fp_offset > 176-16) { avalue[i] = l->overflow_arg_area; l->overflow_arg_area = (char *)l->overflow_arg_area + 8; } else { avalue[i] = (char *)l->reg_save_area + l->fp_offset; l->fp_offset += 16; } }#if DEBUG_FFI fprintf (stderr, "double arg %d = %g\n", i, *(double *)avalue[i]);#endif break; case FFI_TYPE_FLOAT: { if (l->fp_offset > 176-16) { avalue[i] = l->overflow_arg_area; l->overflow_arg_area = (char *)l->overflow_arg_area + 8; } else { avalue[i] = (char *)l->reg_save_area + l->fp_offset; l->fp_offset += 16; } }#if DEBUG_FFI fprintf (stderr, "float arg %d = %g\n", i, *(float *)avalue[i]);#endif break; default: FFI_ASSERT(0); } argn += ALIGN(arg_types[i]->size, SIZEOF_ARG) / SIZEOF_ARG; i++; } /* Invoke the closure. */ (closure->fun) (cif, rp, avalue, closure->user_data); /* FIXME: Structs not supported. */ FFI_ASSERT(cif->rtype->type != FFI_TYPE_STRUCT); /* Tell ffi_closure_UNIX64 how to perform return type promotions. */ return cif->rtype->type;}#endif /* ifndef __x86_64__ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -