`

Libffi

 
阅读更多
Libffi介绍
高级语言的编译器根据一定的规则生成代码,这些规则对于不同编译器的工作是必须的。其中一个规则叫做“调用规则”(Calling Convention),它包含了编译器关于在函数入口处函数参数位置、函数返回值位置的一系列假设。它有时也被称作“ABI”(Application Binary Interface)。
一些程序在编译时可能不知道传给函数的参数是什么,例如,解释器在运行时才被告知调用给定函数的参数类型和数量。Libffi可以在这些函数中看做是连接要解释的函数和编译后的代码之间的桥梁。
“Libffi”库为多种调用规则提供了可移植的高级语言编程接口,这使得程序员在运行时可以调用任何由调用接口指定的函数。
FFI(Foreign Function Interface)允许以一种语言编写的代码调用另一种语言的代码,而Libffi库提供了最底层的、与架构相关的、完整的FFI,因此在它的上层必须有函数来管理两种语言之间参数的格式转换。
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函数来看,这也可以用在将用户参数和函数指针封装到一个函数指针里面(这正是ffi要做的,因此closure API一定要实现)。

2.2 Android Libffi调用
在/Android2.1/dalvik/vm/Dvm.mk中有以下语句:

ifeq ($(MTERP_ARCH_KNOWN),false)
# unknown architecture, try to use FFI
LOCAL_C_INCLUDES += external/libffi/$(dvm_os)-$(dvm_arch)
LOCAL_SHARED_LIBRARIES += libffi

LOCAL_SRC_FILES += \
   arch/generic/Call.c \
   arch/generic/Hints.c \
   mterp/out/InterpC-allstubs.c
在Android2.1里,对于未知架构android将调用libffi来处理不同语言的函数调用问题,调用的源文件位于/android2.1/dalvik/vm/arch/generic/Calls.c和Hints.c;而对于确定的架构(例如ARM、X86、MIPS等)则采用他们架构相关的方法来处理该问题。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics