当前位置: 首页 > 工具软件 > LibFFI > 使用案例 >

iOS libffi 一些理解

姚德容
2023-12-01

C 语言

  1. 主动调用函数
// - 函数声明
double addFunc(int a, double b){
    return a + b;
}

// - 测试函数
void libffi_add(){

    // - 构造函数模板 包括参数和返回值
    ffi_cif cif;
    ffi_type *argTyeps[2] = { &ffi_type_sint, &ffi_type_double };
    ffi_type *rettype = &ffi_type_double;
    ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, rettype, argTyeps);

    // - 参数
    int a = 100;
    double b = 0.5;
    void *args[2] = { &a , &b};
	double result = 0;
	
    // - 使用cif函数签名信息调用函数
    ffi_call(&cif, (void *)&addFunc, &result, args);
}
  1. 修改函数的实现
// - 修改的函数指针的函数实现
void register_add_func(ffi_cif *cif,void *ret,void **args,void *userdata){
    int a = *(int *)args[0];
    double b = *(double *)args[1];
    *(double *)ret = a + b;
}

void libffi_register_add(){   

    // - 函数模板 
    // - 1. 参数
    unsigned argsCount = 2;
    ffi_type **argTyeps = malloc(sizeof(ffi_type *) * argsCount);
    argTyeps[0] = &ffi_type_sint;
    argTyeps[1] = &ffi_type_double;
    
   // - 2. 返回值
    ffi_type *rettype = malloc(sizeof(void *));
    rettype = &ffi_type_double;
    
    // -  3. 构建函数模板
    ffi_cif *cif = malloc(sizeof(ffi_cif));
    ffi_prep_cif(cif, FFI_DEFAULT_ABI, argsCount, rettype, argTyeps);
   
    // - 绑定 closure 和 add 函数指针
	double (*add)(int, double) = NULL;
    ffi_closure *closure = ffi_closure_alloc(sizeof(ffi_closure), (void *)&add);
   
    // - 自定义传递的参数(需要保持不释放) 实际使用时, ffi_type、ffi_closure和userdata都需要一直存在
    NSString *userdata =  @"123";
    CFRetain((__bridge CFTypeRef)(userdata));
   
    // - 替换函数调用
    /* 执行顺序:
      1. ffi_closure_SYSV_V或者ffi_closure_SYSV
      2. ffi_closure_SYSV_inner
      3. register_add_func
     */
    ffi_prep_closure_loc(closure, cif, &register_add_func, (__bridge void *)(userdata), add);

	// - 测试代码
    double result = add(1, 0.5);
    assert(result == 1.5);
}

OC方法

  1. 主动调用方法
@interface Sark : NSObject @end

@implementation Sark 
- (int)fooWithBar:(int)bar baz:(int)baz {
    return bar + baz;
}
@end

void testFFICall() {
	// - 构建函数模板
	ffi_cif cif;
	ffi_type *argumentTypes[] = {&ffi_type_pointer, &ffi_type_pointer, &ffi_type_sint32, &ffi_type_sint32};    
	ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &ffi_type_pointer, argumentTypes);        

	// - 传递的参数和返回值
	Sark *sark = [Sark new];    
	SEL selector = @selector(fooWithBar:baz:);         
	int bar = 123;    
	int baz = 456;    
	void *arguments[] = {&sark, &selector, &bar, &baz}; 
	int retValue;    

	// - 方法调用, 在 
	IMP imp = [sark methodForSelector:selector];       
	ffi_call(&cif, imp, &retValue, arguments);    
	NSLog(@"ffi_call: %d", retValue);
}
  1. 修改方法实现
@interface Sark : NSObject @end

@implementation Sark 
- (int)fooWithBar:(int)bar baz:(int)baz {
    return bar + baz;
}
@end

// - 修改方法提的实现
void closureCalled(ffi_cif *cif, void *ret, void **args, void *userdata) {
    int bar = *((int *)args[2]);    
    int baz = *((int *)args[3]);    
   *((int *)ret) = bar * baz;
}

void testFFIClosure() {
	// - 构建函数模板, 
    ffi_cif cif;    
    ffi_type *argumentTypes[] = {&ffi_type_pointer, &ffi_type_pointer, &ffi_type_sint32, &ffi_type_sint32};
	ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 4, &ffi_type_pointer, argumentTypes);       
        
	// - 关联 IMP 和 ffi_closure
	IMP newIMP; 
	ffi_closure *closure = ffi_closure_alloc(sizeof(ffi_closure), (void *)&newIMP); 

	// 关联 closure 和  cif 和 closureCalled
	ffi_prep_closure_loc(closure, &cif, closureCalled, NULL, NULL); 

	//  - 使用 runtime 接口动态地将 fooWithBar:baz 方法绑定到 closureCalled 函数指针上    
	Method method = class_getInstanceMethod([Sark class], @selector(fooWithBar:baz:));    
	method_setImplementation(method, newIMP);

	// - 测试代码 
	// - 构建函数模板时候, 不必传入值, 但是传入了参数个数和参数大小, 这样在栈中取值得时候, 可以取到值
	// - 在调用fooWithBar:baz:方法时 参数应该是压入栈中或者存在寄存器中, 在closureCalled中使用这些参数时候, 应该是直接去栈中/寄存器中取的.
	
	Sark *sark = [Sark new];    
	int ret = [sark fooWithBar:123 baz:456];   
	NSLog(@"ffi_closure: %d", ret);
}
 类似资料: