Gcc動態連結

函式名稱
dlopen, dlclose, dlerror, dlsym - 動態連結載入器的可程式介面函式

摘要
#include <= 標頭檔
void *dlopen(const char *filename, int flag);
char *dlerror(void);
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);
編譯時使用 –ldl 進行動態函式庫連結.

說明
這dlopen(), dlsym(), dlclose(), dlerror() 四個函式是執行動態連結載入器的介面函式。

函數 dlerror() 以文字形式回傳錯誤發生的原因,若初始化或最後一次呼叫均無錯誤,則回傳NULL

函數 dlopen() 載入一個動態函式庫檔名,並回傳一個"handle"作為動態函式庫的指標,如果檔案名為 NULL,則回傳主程式的指標。

dlopen函式所使用的flag參數,必須包括以下兩個值其中之一:

RTLD_LAZY
執行懶散繫結。只有參照它們的代碼被執行時才解析符號。如果從未被參照的符號,它是永遠不會被解析。(此模式只對函式參照有效;對變數的參照則是立即進行函式庫繫結)。

RTLD_NOW
若是這個值被指定,或是LD_BIND_NOW這個環境變數被設定成一個非空字串,所有在函式庫中未定義的符號將在dlopen()返回前被解析,若無法完成解析將傳回錯誤訊息。

下列零或多個值也可與flag值進行OR的(使用 "|" 符號)組合運用:

RTLD_GLOBAL
函式庫定義的符號可被隨後載入的其他函式庫重新解析定義。

RTLD_LOCAL
與RTLD_GLOBAL相反,若沒有特別指定,RTLD_LOCAL將為預設值.函式庫定義的
符號不能被隨後載入的其他函式庫重新解析定義。

RTLD_NODELETE (since glibc 2.2)
在 dlclose() 執行期間不卸載函式庫。因此,如果函式庫在以後重新使用dlopen()
載入, 這個函式庫靜態變數將不會重新初始化。
這個flag在POSIX.1-2001標準中未被指定。

RTLD_NOLOAD (since glibc 2.2)
不載入函式庫。這可用於測試函式庫是否已經存在 (dlopen() 回傳 NULL表示不
存在,否則則是已存在)。
這個flag在POSIX.1-2001標準中未被指定。

RTLD_DEEPBIND (since glibc 2.3.4 )
在搜索全域符號前先搜索函式庫內的符號
這個flag在POSIX.1-2001標準中未被指定。

函式 dlsym() 使用dlopen()函式傳回的動態函式庫指標(handle)及
符號名稱作為函式參數,成功執行後,回傳符號載入到記憶體中的
位址,如果該符號找不到,dlsym() 則回傳NULL值。

函式 dlclose() 逐步遞減動態函式庫handle指標的參照計數。如果參照計數降到零,沒有其他已載入的函式庫使用符號,這時動態函式庫將被卸載。
函式 dlclose()回傳值為0代表成功,非0則代表有錯誤發生。

範例
載入 math 函式庫, 算出cosine(2.0)的值:

#include
#include
#include

int
main(int argc, char **argv)
{
void *handle;
double (*cosine)(double);
char *error;

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(). */

*(void **) (&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);
}

上述範例程式檔名取名為"foo.c", 讀者可使用下列指令編譯程式:
$ gcc -rdynamic -o foo foo.c -ldl
執行foo程式,結果如下:
$ ./foo
-0.416147

BB 發表在 痞客邦 PIXNET 留言(0) 人氣()