1.2 如何使用FFI
1.2.1 FFI使用流程
Libffi假设你有要调用的函数的指针、要传递的参数的类型和数量以及该函数返回值的类型。
第一步你必须创建与你要调用的函数特征相匹配的“ffi_cif”对象,这是单独的一步因为多次调用一个“ffi_cif”对象很常见(其中的“cif”指的是Call Interface)。要创建“ffi_cif”对象必须调用函数“ffi_prep_cif”。
声明位置:android2.1/external/libffi/include/ffi_real.h Line 348
ffi_status ffi_prep_cif(ffi_cif *cif,
ffi_abi abi,
unsigned int nargs,
ffi_type *rtype,
ffi_type **atypes);
实现位置:android/external/Libffi/src/prep_cif.c Line 88
ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,ffi_type *rtype, ffi_type **atypes)
参数解释:
abi:要使用的ABI,通常使用FFI_DEFAULT_ABI就可以了;
nargs:函数接受的参数的数量;
rtype:指向FFI_TYPE结构体的指针,描述函数的返回类型;
argtypes:FFI_TYPE结构体的向量,其中必须包含nargs元素。
ffi_prep_cif返回“ffi_status”类型变量,如果初始化正确则返回“FFI_OK”,如果一个“ffi_type”对象错误则返回“FFI_BAD_TYPEDEF”,如果ABI参数错误则返回“FFI_BAD_ABI”。
第二步你必须调用“ffi_call”函数来调用初始化的“ffi_cif”对象。
声明位置:android2.1/external/libffi/include/ffi_real.h Line 354
void ffi_call(ffi_cif *cif,
void (*fn)(void),
void *rvalue,
void **avalue);
实现位置:由android2.1/external/libffi/src下各架构中ffi.c实现
参数解释:
cif:由“ffi_prep_cif”指定的cif;
fn:根据cif的不同调用函数fn;
rvalue:一块内存的指针,存放函数调用返回的结果。它必须足够大并且合理分配,由调用者负责确保这一点;
avalue:一个“void *”指针用来指向保存调用函数参数的存放地址。
2、Android2.1 Libffi的实现
2.1 FFI的实现
在Android2.1中Libffi整体作为外部文件放在/external/libffi实现,其目录架构如下:
目录:/android2.1/external/libffi/
主要结构分析:
-doc libffi的文档管理。
--libffi.info libffi的介绍;
--libffi.texi 定义了libffi需要的部分API,可以看成是定义了部分全局变量;
--stamp-vti (?)版本管理的记录;
--version.texi 同上;
-include 头文件。
--ffi.h.in 定义了libffi需要的部分API,可以看成是定义了部分全局变量;
--ffi_common.h 定义了编译libffi必须的内部变量和宏;
--ffi_real.h 内容几乎同ffi.h.in,仅将与架构相关的几行重新另写为ffitarget.h放
在/android2.1/external/libffi/src/各个架构下面;
--Makefile.am Makefile文件,指定头文件的编译过程,由上层make调用;
--Makefile.in Makefile.am生成;
-linux-arm arm架构的头文件。
--ffi.h arm架构下ffi所需的头文件;
--fficonfig.h arm架构下ffi配置文件,定义了一些宏;
-linux-x86 x86架构的头文件。
--ffi.h x86架构下ffi所需的头文件(和arm下几乎一样);
--fficonfig.h x86架构下ffi配置文件,定义了一些宏(和arm下几乎一样,多定
义了一些宏);
-man (?)重要函数几乎的机器语言解释。
--ffi.3 初始化ffi的机器级解释;
--ffi_call.3 ffi_call函数的机器级解释;
--ffi_prep_cif.3 ffi_prep_cif函数的机器级解释;
--Makefile.am Makefile文件,指定编译方法,由上层make调用;
--Makefile.in 由Makefile.am生成;
-src 不同架构下ffi的实现,包括alpha、arm、cris、frv、IA64、M32R、M68K、MIPS、
PA、powerpc、s390、SH、SH64、sparc和X86架构,每个架构有单独的文件夹,下面仅分析arm、x86架构文件夹。
--arm
---ffi.c 实现ffi的基本函数的实现;
--ffitarget.h 头文件,在/…/linux-arm/ffi.h中调用;
--sysv.S 定义了函数ffi_closure_SYSV、ffi_call_SYSV等,实际完成ffi_call等函
数功能;
--x86
--ffi.c 实现ffi的基本函数的实现;
--ffitarget.h 头文件,在/…/linux-arm/ffi.h中调用;
--sysv.S 定义了函数ffi_closure_SYSV、ffi_call_SYSV等,实际完成ffi_call等函
数功能;
--其它文件为*.S,为Darwin、UNIX64、WIN32、FREEBSD操作系统下ffi的汇编实现。
--prep_cif.c 准备好函数的cif;
--closures.c 定义了Closure API相关的方法;
--dlmalloc.c 与内存分配、malloc相关的东西;
--types.c 定义了ffi需要的TYPE;
--raw_api.c 定义了Raw API相关的方法;
--java_raw_api.c 定义了仿Java的Raw API相关的方法,和raw API差不多;
--debug.c debug ffi时需要的方法;
-testsuite (?)测试用的方法,暂时未看。
-Android.mk Makefile文件,只定义了arm和x86架构的编译流程,生成libffi库文件。
-ChangeLog.* 修改日志,可以便于理解。
-compile 编译器需要的,解释-c、-o命令。
-configure.ac 用来生成configure执行文件。
-Makefile.am 整个libffi的编译规则,生成Makefile.in。
其中raw API和closure API是用来传参、封装方法的接口:raw API是用来绕过由架构封装或者未封装的参数;closure API将解释过的函数封装进C指针,从而可以作为C函数来看,这也可以用