函數名 | 功能描述 |
---|---|
dlopen | 打開對象文件,使其可被程序訪問 |
dlsym | 獲取執行了 dlopen 函數的對象文件中的函數的地址 |
dlerror | 該函數沒有參數,它會在發生前面的錯誤時返回一個字符串,同時將其從內存中清空; 在沒有錯誤發生時返回 NULL, |
dlclose |
關閉目標文件。如果無需再調用共享對象的話,應用程序可以調用該方法來通知操作系統不再需要句柄和對象引用了。它完全是按引用來計數的,所以同一個共享對象的多個用戶相互間不會發生衝突(只要還有一個用戶在使用它,它就會待在內存中)。任何通過已關閉的對象的 |
一、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。