This series is mainly used in combination with iOS TypeEncode and libffi.
TypeEncode portal
Making the source code
1. Call a function
About collection types: structures, arrays, etc., more on that later.
1.1 Fixed Parameters
The function declaration is as follows
double addFunc(int a, double b){
return a + b;
}
Copy the code
Libffi call
void libffi_add(){ ffi_cif cif; // Parameter values int a = 100; Double b = 0.5; void *args[2] = { &a , &b}; // Array of parameter types ffi_type *argTyeps[2] = {&ffi_type_sint, &ffi_type_double}; ffi_type *rettype = &ffi_type_double; Cfi ffi_prep_cif(&CIF, FFI_DEFAULT_ABI, sizeof(args)/sizeof(void *), rettype, argTyeps); // Double result = 0; Ffi_call (&cif, (void *) &addfunc, &result, args); // assert assert(result == 100.5); }Copy the code
1.2 Variable Parameters
I’m using NSLog here for example
Call using libffi
void libffi_nslog(){ ffi_cif cif; // Parameter value NSString *format = @"%@"; NSString *value = @"123"; void *args[2] = { &format , &value}; // Array of parameter types ffi_type *argTyeps[2] = {&ffi_type_pointer, &ffi_type_pointer}; ffi_type *rettype = &ffi_type_void; Cfi ffi_prep_cif(&CIF, FFI_DEFAULT_ABI, sizeof(argTyeps)/sizeof(void *), rettype, argTyeps); // void NSLog(NSString *format,...) The first argument is a pointer, and all other arguments are on the stack cif. aARCH64_nfixedargs = 1; Endif // Use the cif function to sign the information and call the function. // The reason for passing NULL here is that the return pointer is not used when the return value is void, as described in a later implementation. ffi_call(&cif, (void *)&NSLog, NULL, args); }Copy the code
2. Register functions
2.1 Fixed Parameters
Called function
void register_add_func(ffi_cif *cif,void *ret,void **args,void *userdata){ assert([(__bridge NSString *)userdata isEqualToString:@"123"]); // We can dynamically obtain parameters based on the cif parameter type and return value type. Double (*add)(int, double) int a = *(int *)args[0]; double b = *(double *)args[1]; *(double *)ret = a + b; }Copy the code
Libffi registers and calls functions
void libffi_register_add(){ double (*add)(int, double) = NULL; Cfi unsigned argsCount = 2 based on the argument and return value type; ffi_type **argTyeps = malloc(sizeof(ffi_type *) * argsCount); argTyeps[0] = &ffi_type_sint; argTyeps[1] = &ffi_type_double; ffi_type *rettype = malloc(sizeof(void *)); rettype = &ffi_type_double; ffi_cif *cif = malloc(sizeof(ffi_cif)); ffi_prep_cif(cif, FFI_DEFAULT_ABI, argsCount, rettype, argTyeps); Closure *closure = ffi_cloSURE_alloc (sizeof(ffi_closure), (void *)&add); // Generate ffi_closure *closure = ffi_cloSURE_alloc (sizeof(ffi_closure)); NSString * userData = @"123"; CFRetain((__bridge CFTypeRef)(userdata)); // replace add with closure 1. Ffi_closure_SYSV_V or ffi_closure_SYSV 2. ffi_closure_SYSV_inner 3. Register_add_func */ ffi_prep_closure_loc(closure, cif, ®ister_add_func, (__bridge void *)(userdata), add); Double result = add(1, 0.5); Assert (result = = 1.5); }Copy the code
2.2 Variable Parameters
Similar to 1.2, cfI can be modified.