📄 ffi.c
字号:
void *user_data){#ifdef POWERPC64 void **tramp = (void **) &closure->tramp[0]; FFI_ASSERT (cif->abi == FFI_LINUX64); /* Copy function address and TOC from ffi_closure_LINUX64. */ memcpy (tramp, (char *) ffi_closure_LINUX64, 16); tramp[2] = (void *) closure;#else unsigned int *tramp; FFI_ASSERT (cif->abi == FFI_GCC_SYSV || cif->abi == FFI_SYSV); tramp = (unsigned int *) &closure->tramp[0]; tramp[0] = 0x7c0802a6; /* mflr r0 */ tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */ tramp[4] = 0x7d6802a6; /* mflr r11 */ tramp[5] = 0x7c0803a6; /* mtlr r0 */ tramp[6] = 0x800b0000; /* lwz r0,0(r11) */ tramp[7] = 0x816b0004; /* lwz r11,4(r11) */ tramp[8] = 0x7c0903a6; /* mtctr r0 */ tramp[9] = 0x4e800420; /* bctr */ *(void **) &tramp[2] = (void *)ffi_closure_SYSV; /* function */ *(void **) &tramp[3] = (void *)closure; /* context */ /* Flush the icache. */ flush_icache(&closure->tramp[0],FFI_TRAMPOLINE_SIZE);#endif closure->cif = cif; closure->fun = fun; closure->user_data = user_data; return FFI_OK;}typedef union{ float f; double d;} ffi_dblfl;int ffi_closure_helper_SYSV (ffi_closure*, void*, unsigned long*, ffi_dblfl*, unsigned long*);/* Basically the trampoline invokes ffi_closure_SYSV, and on * entry, r11 holds the address of the closure. * After storing the registers that could possibly contain * parameters to be passed into the stack frame and setting * up space for a return value, ffi_closure_SYSV invokes the * following helper function to do most of the work */intffi_closure_helper_SYSV (ffi_closure* closure, void * rvalue, unsigned long * pgr, ffi_dblfl * pfr, unsigned long * pst){ /* rvalue is the pointer to space for return value in closure assembly */ /* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */ /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV */ /* pst is the pointer to outgoing parameter stack in original caller */ void ** avalue; ffi_type ** arg_types; long i, avn; long nf; /* number of floating registers already used */ long ng; /* number of general registers already used */ ffi_cif * cif; double temp; unsigned size; cif = closure->cif; avalue = alloca(cif->nargs * sizeof(void *)); size = cif->rtype->size; nf = 0; ng = 0; /* Copy the caller's structure return value address so that the closure returns the data directly to the caller. For FFI_SYSV the result is passed in r3/r4 if the struct size is less or equal 8 bytes. */ if (cif->rtype->type == FFI_TYPE_STRUCT) { if (!((cif->abi == FFI_SYSV) && (size <= 8))) { rvalue = (void *) *pgr; ng++; pgr++; } } 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: /* there are 8 gpr registers used to pass values */ if (ng < 8) { avalue[i] = (((char *)pgr)+3); ng++; pgr++; } else { avalue[i] = (((char *)pst)+3); pst++; } break; case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: /* there are 8 gpr registers used to pass values */ if (ng < 8) { avalue[i] = (((char *)pgr)+2); ng++; pgr++; } else { avalue[i] = (((char *)pst)+2); pst++; } break; case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: case FFI_TYPE_POINTER: /* there are 8 gpr registers used to pass values */ if (ng < 8) { avalue[i] = pgr; ng++; pgr++; } else { avalue[i] = pst; pst++; } break; case FFI_TYPE_STRUCT: /* Structs are passed by reference. The address will appear in a gpr if it is one of the first 8 arguments. */ if (ng < 8) { avalue[i] = (void *) *pgr; ng++; pgr++; } else { avalue[i] = (void *) *pst; pst++; } break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: /* passing long long ints are complex, they must * be passed in suitable register pairs such as * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) * and if the entire pair aren't available then the outgoing * parameter stack is used for both but an alignment of 8 * must will be kept. So we must either look in pgr * or pst to find the correct address for this type * of parameter. */ if (ng < 7) { if (ng & 0x01) { /* skip r4, r6, r8 as starting points */ ng++; pgr++; } avalue[i] = pgr; ng+=2; pgr+=2; } else { if (((long)pst) & 4) pst++; avalue[i] = pst; pst+=2; } break; case FFI_TYPE_FLOAT: /* unfortunately float values are stored as doubles * in the ffi_closure_SYSV code (since we don't check * the type in that routine). */ /* there are 8 64bit floating point registers */ if (nf < 8) { temp = pfr->d; pfr->f = (float)temp; avalue[i] = pfr; nf++; pfr++; } else { /* FIXME? here we are really changing the values * stored in the original calling routines outgoing * parameter stack. This is probably a really * naughty thing to do but... */ avalue[i] = pst; nf++; pst+=1; } break; case FFI_TYPE_DOUBLE: /* On the outgoing stack all values are aligned to 8 */ /* there are 8 64bit floating point registers */ if (nf < 8) { avalue[i] = pfr; nf++; pfr++; } else { if (((long)pst) & 4) pst++; avalue[i] = pst; nf++; pst+=2; } break; default: FFI_ASSERT(0); } i++; } (closure->fun) (cif, rvalue, avalue, closure->user_data); /* Tell ffi_closure_SYSV how to perform return type promotions. Because the FFI_SYSV ABI returns the structures <= 8 bytes in r3/r4 we have to tell ffi_closure_SYSV how to treat them. */ if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT && size <= 8) return FFI_SYSV_TYPE_SMALL_STRUCT + size; return cif->rtype->type;}int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure*, void*, unsigned long*, ffi_dblfl*);int FFI_HIDDENffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, unsigned long *pst, ffi_dblfl *pfr){ /* rvalue is the pointer to space for return value in closure assembly */ /* pst is the pointer to parameter save area (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */ /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */ void **avalue; ffi_type **arg_types; long i, avn; ffi_cif *cif; ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; cif = closure->cif; avalue = alloca (cif->nargs * sizeof (void *)); /* Copy the caller's structure return value address so that the closure returns the data directly to the caller. */ if (cif->rtype->type == FFI_TYPE_STRUCT) { rvalue = (void *) *pst; pst++; } 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: avalue[i] = (char *) pst + 7; pst++; break; case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: avalue[i] = (char *) pst + 6; pst++; break; case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: avalue[i] = (char *) pst + 4; pst++; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_POINTER: avalue[i] = pst; pst++; break; case FFI_TYPE_STRUCT: /* Structures with size less than eight bytes are passed left-padded. */ if (arg_types[i]->size < 8) avalue[i] = (char *) pst + 8 - arg_types[i]->size; else avalue[i] = pst; pst += (arg_types[i]->size + 7) / 8; break; case FFI_TYPE_FLOAT: /* unfortunately float values are stored as doubles * in the ffi_closure_LINUX64 code (since we don't check * the type in that routine). */ /* there are 13 64bit floating point registers */ if (pfr < end_pfr) { double temp = pfr->d; pfr->f = (float) temp; avalue[i] = pfr; pfr++; } else avalue[i] = pst; pst++; break; case FFI_TYPE_DOUBLE: /* On the outgoing stack all values are aligned to 8 */ /* there are 13 64bit floating point registers */ if (pfr < end_pfr) { avalue[i] = pfr; pfr++; } else avalue[i] = pst; pst++; break;#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE case FFI_TYPE_LONGDOUBLE: if (pfr + 1 < end_pfr) { avalue[i] = pfr; pfr += 2; } else { if (pfr < end_pfr) { /* Passed partly in f13 and partly on the stack. Move it all to the stack. */ *pst = *(unsigned long *) pfr; pfr++; } avalue[i] = pst; } pst += 2; break;#endif default: FFI_ASSERT(0); } i++; } (closure->fun) (cif, rvalue, avalue, closure->user_data); /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ return cif->rtype->type;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -