2014年12月15日 星期一

[Linux] dlopen 和 dlsym

我都說這些是放再經書 (C tools) 最末頁妖魔鬼怪API ....

原理網路上很多,這裡簡單筆記就好。

dlopen和dlsym是用於打開動態鏈接庫中的函數,將動態鏈接庫中的函數或類導入到本程序中:
dlopen函數:
功能:打開一個動態鏈接庫

dlsym函數:
  函數原型是
  void* dlsym(void* handle,const char* symbol)
  該函數在<dlfcn.h>文件中。
  handle是由dlopen打開動態鏈接庫後返回的指針,symbol就是要求獲取的函數的名稱,函數  返回值是void*,指向函數的地址,供調用使用。

先寫一個so 來讀:
root@bejo:/home/bejo/code/test# cat libso.c
#include <stdio.h>

int bejo_lib(char *name, int i)
{
    printf("I am %s, do i=%d\n", name, i);

    return 0;
}

包成 dynamic using
#gcc -c libso.c
#gcc -shared -o libso.so libso.o


寫一個使用者~*
root@bejo:/home/bejo/code/test# cat use.c
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(int *argc, char **argv)
{
    void *fHandle;
    void (*func)();

    fHandle = dlopen("./libso.so",RTLD_LAZY);

    if (!fHandle) {
        fprintf (stderr, "%s\n", dlerror());
        exit(1);
    }
    dlerror();

    func = (void(*)())dlsym(fHandle,"bejo_lib");

    if (func) {
        func("BEJO", 999);
    }

    dlclose(fHandle);
    return 0;
}

包一包,記得加上 -ldl   ---> libdl.so
#gcc use.c -ldl -o use#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(int *argc, char **argv)
{
    void *fHandle;
    double (*func)();

    fHandle = dlopen("./libm.so.6",RTLD_LAZY);

    if (!fHandle) {
        fprintf (stderr, "%s\n", dlerror());
        exit(1);
    }
    dlerror();

    func = (double(*)())dlsym(fHandle,"fabs");

    if (func) {
        printf("fabs = %f\n", func(-12.345));
    }

    dlclose(fHandle);
    return 0;
}

# ./use
I am BEJO, do i=999

--
上面其實都在工具書可以查到



這本真的是聖經阿....

來作點無聊的事...
如果你手上拿到一個陌生的so 檔又想跑跑看?
ex:
#cp  cp /lib/i386-linux-gnu/libm.so.6
這個好了。lib math

那就:
#readelf -s libm.so.6 | grep fabs
 0000bdb0     7 FUNC    WEAK   DEFAULT   13 fabs@@GLIBC_2.0

有耶,這是一個把浮點數取決對值的方法

修改一下use.c

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(int *argc, char **argv)
{
    void *fHandle;
    double (*func)();

    fHandle = dlopen("./libm.so.6",RTLD_LAZY);

    if (!fHandle) {
        fprintf (stderr, "%s\n", dlerror());
        exit(1);
    }
    dlerror();

    func = (double(*)())dlsym(fHandle,"fabs");

    if (func) {
        printf("fabs = %f\n", func(-12.345));
    }

    dlclose(fHandle);
    return 0;
}

輸出:
# ./use
fabs = 12.345000

恩...  好吧。我真無聊  囧>

其實這幾個function 就在工具書裡面,尤其是最末頁幾個妖魔鬼怪專用API,平常工作開發不大會用到,有看到也就review open source 的時候
這次跟其他部門合作剛好有開發到,負責撰寫*.so 檔,來切開開發工作。
平行的開發方法很多種技巧,像常見的靠include 來切割C files、module 。 
而這種不需要header 的方式,讓開發平行很多。
也非常適合來作 user space 的insert packaget module 

妖魔鬼怪還有一組 share memory API 剛好這次噴bug 在這裡,下次再來筆記一下。