so库生成和用法汇总

函数名 功能描述
dlopen 打开对象文件,使其可被程序访问
dlsym 获取执行了 dlopen 函数的对象文件中的函数的地址
dlerror 该函数没有参数,它会在发生前面的错误时返回一个字符串,同时将其从内存中清空; 在没有错误发生时返回 NULL,
dlclose

关闭目标文件。如果无需再调用共享对象的话,应用程序可以调用该方法来通知操作系统不再需要句柄和对象引用了。它完全是按引用来计数的,所以同一个共享对象的多个用户相互间不会发生冲突(只要还有一个用户在使用它,它就会待在内存中)。任何通过已关闭的对象的 dlsym 解析的符号都将不再可用

一、so库生成:

新建一个sort.c文件,写排序函数

使用gcc -o libsort.so -fPIC -shared sort.c产生libsort.so库。

 fPIC :(Position Independent Code)地址无关代码,fPIC的作用

Linux位置无关代码实现,浅谈位置无关代码_weixin_39521520的博客-CSDN博客

void InsertSort(int* a,int len)
{
    int begin = 1;
    int i = 0;
    while(begin < len)
    {
        int key = a[begin];
        for(i = begin-1;i>=0;i--)
        {
            if(a[i]<=key)
            {
                a[i+1] = key;
                break;
            }
            a[i+1] = a[i];
        }
        if(i<0)
            a[0] = key;
        begin++;
    }

}

二、.so库有两种调用方法:

1.编译过程中连接到可执行程序,

2.用dlopen()动态加载

链接法

新建main.c文件:

使用命令gcc -o main main.c -lsort -L.编译。

  • -L. 表示.so库在当前目录下;
  • -lsort表示调用libsort.so库
    程序运行之前,要先使用命令export LD_LIBRARY_PATH=$(pwd),即.so库的路径添加到环境变量中,因为程序运行时会先加载所依赖的so库到内存中,so加载成功后才真正启动程序。
    运行./main后输出递增序列,调用成功。
#include 
int main()
{
    int i = 0;
    int test[]={1,3,5,7,2,4,6,8};
    InsertSort(test,8);
    for(i=0;i<8;i++)
    {
        printf("%d,",test[i]);
    }
    printf("\n");
    return 0;
}

dlopen

新建main2.c文件:

使用命令gcc -o main2 main2.c -ldl编译。动态加载.so库的话需要-ldl。
运行./main2后输出递增序列,调用成功。

#include 
#include 
#include 
int main()
{
    int i = 0;
    int test[]={1,3,5,7,2,4,6,8};
    int (*sort)(int*,int);
    void *handle = dlopen("./libsort.so",RTLD_LAZY);
    if(!handle)
    {
        printf("dlopen error :%s\n",dlerror());
        return -1;
    }
    sort = dlsym(handle,"InsertSort");
    if(!sort)
    {
        printf("dlsym error :%s\n",dlerror());
    }
    sort(test,8);
    dlclose(handle);
    for(i=0;i<8;i++)
        printf("%d,",test[i]);
    printf("\n");
    return 0;
}

三、查看so库的符号表

readelf -s private.so
nm -D private.so

readelf nm objdump 命令详解

readelf nm objdump 命令详解_耿小渣的博客-CSDN博客_nm objdump

nm和readelf命令的区别 - foo__hack - 博客园

四、动态库(.so)隐藏函数名

向客户提供动态链接库(.so)时,有些关键的函数名不希望暴露出去,此时便可以通过gcc的-fvisibility=hidden选项对编译生成的so进行函数符号隐藏,如:LOCAL_CPPFLAGS +=-fvisibility=hidden,执行编译后,使用nm -D xxx.so命令或者readelf --symbols xxx.so查看函数名的确被隐藏,但此时是将所有函数名都隐藏了,那么客户加载so时需要调用的接口函数名(xxx)也会找不到定义,导致编译报undefined reference to xxx错误,所以需要暴露(导出)的函数前应该增加属性__attribute__ ((visibility("default")))设置成可见

五、GNU C++的符号改编机制

例如,全局函数int structure_func(int i, struct test s, double d),其经过符号改编后,函数名变成了_Z14structure_funci4testd

你可能感兴趣的:(知识总结,c语言,c++,蓝桥杯)