參考 參考-1
參考-2
基本介紹 使用 dlopen 和 dlsym 可以使用 so 檔
將 so 檔裡面的函式取出來使用,達到動態替換函式的方法
1 2 3 4 #include <dlfcn.h> void *dlopen (const char *filename, int flag); void *dlsym (void *handle, const char *symbol); int dlclose (void *handle);
首先 man dlopen 可以看到範例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 //Load the math library, and print the cosine of 2.0: #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> int main(int argc, char **argv) { void *handle; // 建立一個 function 名叫 cosine // 需要傳入 double 類型參數並會回傳 double double (*cosine)(double); char *error; // 打開 libm.so 動態函示庫 handle = dlopen("libm.so", RTLD_LAZY); if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(EXIT_FAILURE); } dlerror(); /* Clear any existing error */ /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos"); would seem more natural, but the C99 standard leaves casting from "void *" to a function pointer undefined. The assignment used below is the POSIX.1-2003 (Technical Corrigendum 1) workaround; see the Rationale for the POSIX specification of dlsym(). */ // 將 libm.so 裡面的 cos 函式取出並指派給 cosine //*(void **) (&cosine) = dlsym(handle, "cos"); // 可以改寫成以下這種寫法比較容易閱讀 cosine = dlsym(handle, "cos"); if ((error = dlerror()) != NULL) { fprintf(stderr, "%s\n", error); exit(EXIT_FAILURE); } printf("%f\n", (*cosine)(2.0)); dlclose(handle); exit(EXIT_SUCCESS); }
編譯測試 -ldl
就是 link “dl module” 的意思,而 dl module = libdl.so
編譯出來的執行檔為 8908
如果把檔案改為直接呼叫函式,執行檔為 8552
1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> #include <stdlib.h> #include <math.h> int main(void) { printf ("%f\n", cos(2.0)); return 0; } # 編譯 gcc -o main main.c
實際製作測試 實際要製作兩個檔案
1 2 1. 動態函示庫檔案 (libTest.c) 2. 使用動態動態函示庫 (main.c)
首先是libTest.c
,內容如下
1 2 3 4 5 6 #include <stdio.h> int jasonAdd(int a, int b) { printf("%d add %d = %d\n", a, b, a+b ); return (a+b); }
編譯步驟如下
1 2 1.編譯為目的檔 : gcc -fPIC -c libTest.c 2.目的檔轉為動態函示庫 : gcc -fPIC -shared -o libTest.so libTest.o
接著是main.c
,內容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> int main(int *argc, char **argv) { void *fHandle; int (*func)(int, int); // 注意傳入參數和回傳參數的型態 fHandle = dlopen("./libTest.so",RTLD_LAZY); if (!fHandle) { fprintf (stderr, "%s\n", dlerror()); exit(1); } dlerror(); func = dlsym(fHandle, "jasonAdd"); if (func) { printf("Result = %d\n",func(10,20)); } dlclose(fHandle); return 0; }
編譯步驟和執行結果如下
1 2 3 4 $ gcc -o main main.c -ldl $ ./main 10 add 20 = 30 Result = 30
其他 動態函示庫名稱沒有限定要libXXX
例如你取名為jasonLIB.so
也是可以的,只是習慣以libXXX
命名
使用 .so 前提是你知道裡面函式的參數與回傳值
否則你再定義 function pointer 時也不知道怎麼定義
另外其實你可以使用objdump -T jasonLIB.so
來 dump 函示庫 symbol,可以看出有哪些函式可使用
但還是看不出參數型態數量以及回傳值型態