linux动态库(二)

来源:互联网 发布:mysql数据库备份还原 编辑:程序博客网 时间:2024/06/06 05:53

上篇文章呈现了linux下动态库的一个简单实现,其接口按通用的方式导出,测试程序可以直接调用,本篇展现一个导出函数列表的方式,可以通过函数列表实现对接口的调用

头文件

/*  @ File Name: calc.h  @ Author: hw  @ Mail: feiyelove@163.com  @ Created Time: 2015-07-01 14:42:00*/#ifndef _CALC_H_#define _CALC_H_#ifdef __cplusplusextern "C"{#endifint add(int a, int b);int sub(int a, int b);typedef struct _CALC_FUNCLIST {        int version;        int (*fnadd)(int a, int b);        int (*fnsub)(int a, int b);}CALC_FUNCLIST;typedef CALC_FUNCLIST* CALC_FUNCLIST_PTR;typedef CALC_FUNCLIST_PTR* CALC_FUNCLIST_PTR_PTR;int GetFunclist(CALC_FUNCLIST_PTR_PTR ppFuncList);typedef void (*GET_FUNCLIST_PTR)(CALC_FUNCLIST_PTR_PTR ppFuncList);#ifdef __cplusplus} #endif        #endif

源文件

/*  @ File Name: calc.c  @ Author: hw  @ Mail: feiyelove@163.com  @ Created Time: 2015-07-01 14:39:26*/#include "calc.h"#ifdef __cplusplusextern "C"{#endifint add(int a, int b){        return a + b;}int sub(int a, int b){        return a - b;}static CALC_FUNCLIST m_functionList ={        0x01000001,     // Version        add,        sub};int GetFunclist(CALC_FUNCLIST_PTR_PTR ppFuncList){        *ppFuncList = &m_functionList;        return 0;}#ifdef __cplusplus}#endif

测试程序1

/*  @ File Name: test1.c  @ Author: hw  @ Mail: feiyelove@163.com  @ Created Time: 2015-07-01 17:50:16*/#include <stdio.h>#include <stdlib.h>#include "calc.h"int main(){        CALC_FUNCLIST_PTR pFuncList;        GetFunclist(&pFuncList);        printf("test add [ 1+2 = %d]\n", pFuncList->fnadd(1,2));        printf("test sub [ 1-2 = %d]\n", pFuncList->fnsub(1,2));        return 0;}

测试程序2

/*  @ File Name: test2.c  @ Author: hw  @ Mail: feiyelove@163.com  @ Created Time: 2015-08-25 09:49:41*/#include <stdio.h>#include <stdlib.h>#include <dlfcn.h>#include "calc.h"#define LIBNAME "./libcalc.so"int main(int argc, char *argv[]){        void *handle;        int (*pFunc)(int,int);        CALC_FUNCLIST_PTR pFuncList;        GET_FUNCLIST_PTR ppFuncList;        handle = dlopen(LIBNAME, RTLD_NOW);        if (handle == NULL) {                printf("%s", dlerror());                return -1;        }        pFunc = dlsym(handle, "add");        printf("test add [ 1+2 = %d]\n",pFunc(1,2));        pFunc = dlsym(handle, "sub");        printf("test sub [ 1-2 = %d]\n",pFunc(1,2));        ppFuncList = (GET_FUNCLIST_PTR)dlsym(handle, "GetFunclist");        ppFuncList(&pFuncList);        printf("test add [ 1+2 = %d]\n", pFuncList->fnadd(1,2));        printf("test sub [ 1-2 = %d]\n", pFuncList->fnsub(1,2));        dlclose(handle);        return 0;}

Makefile

CC      = gccCFLAGS  =LDFLAGS = -shared -fPICINC     = -I.LIBS    = -ldlDLL     = libcalc.soOBJS    = calc.o.PHONY:allall:lib test1 test2lib:$(OBJS)        $(CC) $(LDFLAGS) -o $(DLL) $(OBJS)$(OBJS):%.o:%.c        $(CC) $(CFLAGS) $(INC) -c $< -o $@test1:        $(CC) -o test1 test1.c $(DLL) test2:        $(CC) -o test2 test2.c $(LIBS)clean:        rm -f *.o        rm -f $(DLL) test1 test2

编译动态库及测试程序

$ make

查看动态库的导出符号

$ nm -D libcalc.so 00000414 T GetFunclist         w _Jv_RegisterClasses00001590 A __bss_start         w __cxa_finalize         w __gmon_start__00001590 A _edata00001598 A _end00000464 T _fini000002bc T _init000003fc T add00000407 T sub

可以看到,接口GetFunclist add sub都被成功导出,这儿我们将add sub接口也一并导出了,也可以只导出GetFunclist接口,这样的话可以实现对add sub接口的隐藏,当然这只是隐藏接口的一种方式,gcc还提供了一种方法,可以自定义导出函数接口,只需在在编译选项加上-Wl,–version-script=funclist.txt即可,funclist.txt有一定的格式,内部定义了你要导出的接口,如下

{global:add;sub;GetFunclist ;local:*;};

这样便可以自由定义导出接口了
好了,回归正题

执行测试程序1

$ ./test1 test add [ 1+2 = 3]test sub [ 1-2 = -1]

执行测试程序2

./test2 test add [ 1+2 = 3]test sub [ 1-2 = -1]test add [ 1+2 = 3]test sub [ 1-2 = -1]

上述测试程序1展示了函数列表的使用方法,测试程序2展示了动态库的动态加载及调用过程

注意:动态加载注意要加入链接参数-ldl

0 0
原创粉丝点击