Chinaunix首页 | 论坛 | 博客
  • 博客访问: 341576
  • 博文数量: 89
  • 博客积分: 5152
  • 博客等级: 大校
  • 技术积分: 1155
  • 用 户 组: 普通用户
  • 注册时间: 2006-02-25 15:12
文章分类

全部博文(89)

文章存档

2012年(1)

2011年(5)

2010年(14)

2009年(69)

我的朋友

分类: LINUX

2009-04-10 10:50:29

發表於 February 5, 2007 11:54 PM

學到 ELF 的格式,並了解 .text/.data/.bss section 後,接下來絕對不能錯過「ELF loader」領域最經典的題目 - dynamic loader。不把 dynamic loader 從頭到腳好好研究一遍的話,實在是可惜了!

要學習 dynamic loader 的議題,並深入核心實作,最好可以由 ld.so 程式設計的主題切入。ld.so 是 Linux 的 dynamic loader,如果 man ld.so 的話,可以得到以下解釋:

DESCRIPTION
ld.so loads the shared libraries needed by a program, prepares the pro-
gram to run, and then runs it. Unless explicitly specified via the
-static option to ld during compilation, all Linux programs are incom-
plete and require further linking at run time.

與 dynamic loader 有關的系統管理面議題如下,這些是基本功課,應先行了解:

  • /etc/ld.so.conf(ld.so 的設定檔)
  • ldconfig
  • LD_LIBRARY_PATH

ld.so 其實就是我們所熟悉的 /lib/ld-linux.so.2 執行檔。至於 ld.so 的程式設計,則是由以下 3 個主要的函數切入:

#include 
void *dlopen(const char *filename, int flag); 
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);

這個部份可以 'man dlopen',便能得到非常詳盡的說明,同時還有一個範例程式。以下的範例是由 dlopen 的 man page 節錄出來的,我在裡頭加上了註解供您參考:

/* Filename: dl_call.c */
#include
#include
#include

int main(void)
{
void *handle; /* shared library 的 'handle' 指標 */
double (*cosine)(double); /* 指向 shared library 裡的函數 */
char *error; /* 記錄 dynamic loader 的錯誤訊息 */

/* 開啟 shared library 'libm' */
handle = dlopen ("libm.so", RTLD_LAZY);
if (!handle) {
fprintf (stderr, "%s\n", dlerror());
exit(1);
}

dlerror(); /* Clear any existing error */

/* 在 handle 指向的 shared library 裡找到 "cos" 函數,
* 並傳回他的 memory address
*/
cosine = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fprintf (stderr, "%s\n", error);
exit(1);
}

/* indirect function call (函數指標呼叫),
* 呼叫所指定的函數
*/
printf ("%f\n", (*cosine)(2.0));
dlclose(handle);
return 0;
}

dlopen()RTLD_LAZY 參數說明如下(節錄自 man page):

RTLD_LAZY
Perform lazy binding. Only resolve symbols as the code that references
them is executed. If the symbol is never referenced, then it is never
resolved. (Lazy binding is only performed for function references; references
to variables are always immediately bound when the library is loaded.)

由於使用到 dlopen() 函數,編譯時請與 libdl 做連結:

$ gcc -o dl_call dl_call.c -ldl

以上的做法等於:

 printf ("%f\n", cos(2.0));

直接呼叫 libm 的函數時,則是與 libm 做連結:

$ gcc -o dl_call dl_call.c -lm

單純由程式設計的角度來看,利用 dlopen()+dlsym() 來「呼叫函數」與「直接呼叫函數」有什麼應用上的差異呢?事實上,libdl 的使用是很普遍的,許多軟體將自己的功能模組(modules)做成 shared library,並以 dlopen() 載入後使用,由於 shared library 是「可抽換」的,因此可透過 libdl 來做出「Plug-ins」這樣的功能。

--jollen

阅读(497) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~