欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

so库生成和用法汇总

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

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

一、so库生成:

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

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

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)将当前目录设为gcc搜索.so库的路径,否则是找不到.so库的。
    运行./main后输出递增序列,调用成功。
#include <stdio.h>
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 <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
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 命令详解

https://blog.csdn.net/u014608280/article/details/81948141

https://www.cnblogs.com/foohack/p/4103074.html

四、动态库(.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

 

 

 

相关标签: 知识总结