ffi 库使用demo
FFI(Foreign Function Interface)允许以一种语言编写的代码调用另一种语言的代码,而libffi库提供了最底层的、与架构相关的、完整的FFI。libffi的作用就相当于编译器,它为多种调用规则提供了一系列高级语言编程接口,然后通过相应接口完成函数调用,底层会根据对应的规则,完成数据准备,生成相应的汇编指令代码。
动态调用C函数,使用libffi提供接口动态调用流程如下:
1. 准备好参数数据及其对应ffi_type数组、返回值内存指针、函数指针
2. 创建与函数特征相匹配的函数原型:ffi_cif对象
3. 使用“ffi_call”来完成函数调用
补全https://blog.csdn.net/JaimeCool/article/details/76332930中的源码,编译gcc rtl.cpp -fpermissive -w -lffi

结论:
1、指针functionPtr仅仅定义了一个普通数据类型的指针,并没有保证和函数testFunc拥有相同的函数指针类型,这样就可以通用的执行多种类似的函数
可见使用ffi,只要有函数原型cif对象,函数实现指针,返回值内存指针和函数参数数组,我们就可以实现在运行时动态调用任意C函数
#include
#include
#include int testFunc(int m, int n) {printf("params: %d %d \n", m, n);return m+n;
}void testCall (void) {testFunc(1, 2);//拿函数指针// int (*funcPointer)(int, int) = &testFunc;void* functionPtr = &testFunc;int argCount = 2;//参数类型数组ffi_type **ffiArgTypes = alloca(sizeof(ffi_type *) *argCount);ffiArgTypes[0] = &ffi_type_sint;ffiArgTypes[1] = &ffi_type_sint;//参数数据数组void **ffiArgs = alloca(sizeof(void *) *argCount);void *ffiArgPtr = alloca(ffiArgTypes[0]->size);int *argPtr = ffiArgPtr;*argPtr = 5;ffiArgs[0] = ffiArgPtr;void *ffiArgPtr2 = alloca(ffiArgTypes[1]->size);int *argPtr2 = ffiArgPtr2;*argPtr2 = 3;ffiArgs[1] = ffiArgPtr2;//生成函数原型 ffi_cfi 对象ffi_cif cif;ffi_type *returnFfiType = &ffi_type_sint;ffi_status ffiPrepStatus = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, (unsigned int)argCount, returnFfiType, ffiArgTypes);if (ffiPrepStatus == FFI_OK) {//生成用于保存返回值的内存void *returnPtr = NULL;if (returnFfiType->size) {returnPtr = alloca(returnFfiType->size);}//根据cif函数原型,函数指针,返回值内存指针,函数参数数据调用这个函数ffi_call(&cif, functionPtr, returnPtr, ffiArgs);//拿到返回值int returnValue = *(int *)returnPtr;printf("ret: %d \n", returnValue);}
}int main ()
{testCall();return 0;
}
进阶版本,参考llvm中omp的__tgt_rtl_run_target_region处理方法,限制条件设备函数无返回返回值,处理结果通过参数返回

#include
#include
#include
#include
#include
#include
#include #define OFFLOAD_SUCCESS (0)
#define OFFLOAD_FAIL (~0)
#define OFFLOAD_DEVICE_DEFAULT -1#define DPxMOD "0x%0*" PRIxPTR
#define DPxPTR(ptr) ((int)(2 * sizeof(uintptr_t))), ((uintptr_t)(ptr))
// #define DPxPTR(ptr) ptr#define PRIxPTR "l" "x"
#define DEBUG_PREFIX "TARGET aarch64 RTL"#define DEBUGP(prefix, ...) \{ \fprintf(stderr, "%s --> ", prefix); \fprintf(stderr, __VA_ARGS__); \}/// Emit a message for debugging
#define DP(...) \do { \DEBUGP(DEBUG_PREFIX, __VA_ARGS__); \} while (false)#ifdef __cplusplus
extern "C" {
#endifint32_t __tgt_rtl_run_target_region(int32_t device_id, void *tgt_entry_ptr,void **tgt_args, ptrdiff_t *tgt_offsets,int32_t arg_num);int32_t __tgt_rtl_run_target_team_region(int32_t device_id, void *tgt_entry_ptr,void **tgt_args,ptrdiff_t *tgt_offsets,int32_t arg_num, int32_t team_num,int32_t thread_limit,uint64_t loop_tripcount /*not used*/) {// ignore team num and thread limit.// Use libffi to launch execution.ffi_cif cif;// All args are references.std::vector args_types(arg_num, &ffi_type_pointer);std::vector args(arg_num);std::vector ptrs(arg_num);// for (int i=0; irun_region(RTLDeviceID, TgtEntryPtr, TgtVarsPtr, TgtOffsets
int32_t __tgt_rtl_run_target_region(int32_t device_id, void *tgt_entry_ptr,void **tgt_args, ptrdiff_t *tgt_offsets,int32_t arg_num) {// for (int i=0; isize);int *argPtr = ffiArgPtr;*argPtr = 5;ffiArgs[0] = ffiArgPtr;void *ffiArgPtr2 = alloca(ffiArgTypes[1]->size);int *argPtr2 = ffiArgPtr2;*argPtr2 = 3;ffiArgs[1] = ffiArgPtr2;for (i=0; i
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
