📄 ffi.c
字号:
break; case FFI_TYPE_UINT64: case FFI_TYPE_SINT64: cif->flags = FFI_TYPE_UINT64; break; default: cif->flags = FFI_TYPE_INT; break; } /* Lucky us, because of the unique PA ABI we get to do our own stack sizing. */ switch (cif->abi) { case FFI_LINUX: ffi_size_stack_LINUX(cif); break; default: FFI_ASSERT(0); break; } return FFI_OK;}/*@-declundef@*//*@-exportheader@*/extern void ffi_call_LINUX(void (*)(UINT32 *, extended_cif *, unsigned), /*@out@*/ extended_cif *, unsigned, 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; 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) && (cif->rtype->type == FFI_TYPE_STRUCT)) { /*@-sysunrecog@*/ ecif.rvalue = alloca(cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_LINUX: /*@-usedef@*/ debug(2, "Calling ffi_call_LINUX: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn); ffi_call_LINUX(ffi_prep_args_LINUX, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; default: FFI_ASSERT(0); break; }}#if FFI_CLOSURES/* This is more-or-less an inverse of ffi_call -- we have arguments on the stack, and we need to fill them into a cif structure and invoke the user function. This really ought to be in asm to make sure the compiler doesn't do things we don't expect. */UINT32 ffi_closure_inner_LINUX(ffi_closure *closure, UINT32 *stack){ ffi_cif *cif; void **avalue; void *rvalue; UINT32 ret[2]; /* function can return up to 64-bits in registers */ ffi_type **p_arg; char *tmp; int i, avn, slot = FIRST_ARG_SLOT - 1; register UINT32 r28 asm("r28"); cif = closure->cif; /* If returning via structure, callee will write to our pointer. */ if (cif->flags == FFI_TYPE_STRUCT) rvalue = (void *)r28; else rvalue = &ret[0]; avalue = (void **)alloca(cif->nargs * FFI_SIZEOF_ARG); avn = cif->nargs; p_arg = cif->arg_types; for (i = 0; i < avn; i++) { int type = (*p_arg)->type; switch (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_POINTER: slot++; avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: slot += 2; if (slot & 1) slot++; avalue[i] = (void *)(stack - slot); break; case FFI_TYPE_FLOAT: slot++; switch (slot - FIRST_ARG_SLOT) { case 0: fstw(fr4, (void *)(stack - slot)); break; case 1: fstw(fr5, (void *)(stack - slot)); break; case 2: fstw(fr6, (void *)(stack - slot)); break; case 3: fstw(fr7, (void *)(stack - slot)); break; } avalue[i] = (void *)(stack - slot); break; case FFI_TYPE_DOUBLE: slot += 2; if (slot & 1) slot++; switch (slot - FIRST_ARG_SLOT + 1) { case 2: fstd(fr5, (void *)(stack - slot)); break; case 4: fstd(fr7, (void *)(stack - slot)); break; } avalue[i] = (void *)(stack - slot); break; case FFI_TYPE_STRUCT: /* Structs smaller or equal than 4 bytes are passed in one register. Structs smaller or equal 8 bytes are passed in two registers. Larger structures are passed by pointer. */ if((*p_arg)->size <= 4) { slot++; avalue[i] = (void *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size; } else if ((*p_arg)->size <= 8) { slot += 2; if (slot & 1) slot++; avalue[i] = (void *)(stack - slot) + sizeof(UINT64) - (*p_arg)->size; } else { slot++; avalue[i] = (void *) *(stack - slot); } break; default: FFI_ASSERT(0); } p_arg++; } /* Invoke the closure. */ (closure->fun) (cif, rvalue, avalue, closure->user_data); debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0], ret[1]); /* Store the result */ switch (cif->flags) { case FFI_TYPE_UINT8: *(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24); break; case FFI_TYPE_SINT8: *(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24); break; case FFI_TYPE_UINT16: *(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16); break; case FFI_TYPE_SINT16: *(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16); break; case FFI_TYPE_INT: case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: *(stack - FIRST_ARG_SLOT) = ret[0]; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: *(stack - FIRST_ARG_SLOT) = ret[0]; *(stack - FIRST_ARG_SLOT - 1) = ret[1]; break; case FFI_TYPE_DOUBLE: fldd(rvalue, fr4); break; case FFI_TYPE_FLOAT: fldw(rvalue, fr4); break; case FFI_TYPE_STRUCT: /* Don't need a return value, done by caller. */ break; case FFI_TYPE_SMALL_STRUCT3: tmp = (void*)(stack - FIRST_ARG_SLOT); tmp += 4 - cif->rtype->size; memcpy((void*)tmp, &ret[0], cif->rtype->size); break; case FFI_TYPE_SMALL_STRUCT5: case FFI_TYPE_SMALL_STRUCT6: case FFI_TYPE_SMALL_STRUCT7: { unsigned int ret2[2]; int off; /* Right justify ret[0] and ret[1] */ switch (cif->flags) { case FFI_TYPE_SMALL_STRUCT5: off = 3; break; case FFI_TYPE_SMALL_STRUCT6: off = 2; break; case FFI_TYPE_SMALL_STRUCT7: off = 1; break; default: off = 0; break; } memset (ret2, 0, sizeof (ret2)); memcpy ((char *)ret2 + off, ret, 8 - off); *(stack - FIRST_ARG_SLOT) = ret2[0]; *(stack - FIRST_ARG_SLOT - 1) = ret2[1]; } break; case FFI_TYPE_POINTER: case FFI_TYPE_VOID: break; default: debug(0, "assert with cif->flags: %d\n",cif->flags); FFI_ASSERT(0); break; } return FFI_OK;}/* Fill in a closure to refer to the specified fun and user_data. cif specifies the argument and result types for fun. The cif must already be prep'ed. */void ffi_closure_LINUX(void);ffi_statusffi_prep_closure (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data){ UINT32 *tramp = (UINT32 *)(closure->tramp); FFI_ASSERT (cif->abi == FFI_LINUX); /* Make a small trampoline that will branch to our handler function. Use PC-relative addressing. */ tramp[0] = 0xeaa00000; /* b,l .+8, %r21 ; %r21 <- pc+8 */ tramp[1] = 0xd6a01c1e; /* depi 0,31,2, %r21 ; mask priv bits */ tramp[2] = 0x4aa10028; /* ldw 20(%r21), %r1 ; load plabel */ tramp[3] = 0x36b53ff1; /* ldo -8(%r21), %r21 ; get closure addr */ tramp[4] = 0x0c201096; /* ldw 0(%r1), %r22 ; address of handler */ tramp[5] = 0xeac0c000; /* bv %r0(%r22) ; branch to handler */ tramp[6] = 0x0c281093; /* ldw 4(%r1), %r19 ; GP of handler */ tramp[7] = ((UINT32)(ffi_closure_LINUX) & ~2); /* Flush d/icache -- have to flush up 2 two lines because of alignment. */ asm volatile ( "fdc 0(%0)\n" "fdc %1(%0)\n" "fic 0(%%sr4, %0)\n" "fic %1(%%sr4, %0)\n" "sync\n" : : "r"((unsigned long)tramp & ~31), "r"(32 /* stride */)); closure->cif = cif; closure->user_data = user_data; closure->fun = fun; return FFI_OK;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -