2013-03-14 58 views
5

問題是我如何從共享庫(UNIX/LINUX)獲取函數地址?從共享庫獲取函數指針的區別

我在C中編寫了一些測試用例(見下文),在Ubuntu 10.04(amd64)和FreeBSD-8.2(amd64)上編譯和運行。我沒有感覺到任何不同,但我想更多地瞭解可能出現的問題。

在這裏,他們是:

  1. 測試1

lib.c

char* f0(void) { 
    return "Hello, World!"; 
} 

的main.c

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

void *hlib, *addr; 
char* (*foo)(void); 
char* s; 

int main(int argc, char** argv) { 
    if (!(hlib = dlopen("./lib.so", RTLD_LAZY))) 
     return 1; 
    if (!(addr = foo = dlsym(hlib, "f0"))) 
     return 2; 
    s = foo(); 
    printf("%p => %s\n", addr, s); 
    return 0; 
} 

現在構建它:

gcc -o lib.o -c lib.c -Wall -Werror -O3 -fPIC 
gcc -o lib.so -shared -nostartfiles lib.o 
gcc -o main.o -c main.c -Wall -Werror -O3 
gcc -o prog main.o -ldl 

這將打印庫函數f0()的地址和執行結果。

  1. 試驗2

lib.h(在這裏定義動態鏈接庫的標準接口)

#ifndef __LIB_H__ 
#define __LIB_H__ 

typedef struct __syminfo { 
    char* name; // function name 
    void* addr; // function address 
} syminfo_t; 

typedef struct __libinfo { 
    int  num; // number of exported functions 
    syminfo_t sym[1]; // vector of exported function information 
} libinfo_t; 

extern int (*__getinfo)(libinfo_t**); 

#endif 
/* __LIB_H__ 
*/ 

lib.c(庫本身)

#include <stdlib.h> 
#include <lib.h> 

static libinfo_t* li; 

char* foo(void); 

__attribute__((constructor)) void __init() { 
    if ((li = calloc(1, sizeof(libinfo_t)))) { 
    li->num = 1; 
    li->sym[0].name = "foo"; 
    li->sym[0].addr = &foo; 
    } 
} 

__attribute__((destructor)) void __free() { 
    if (li) 
    free(li); 
} 

int getinfo(libinfo_t** inf) { 
    if (!inf) 
    return -1; 
    *inf = li; 
    return 0; 
} 

char* foo(void) { 
    return "Hello, World!"; 
} 

main.c

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

libinfo_t* inf; 

void* hlib; 

int (*__getinfo)(libinfo_t**); 

char* (*foo)(void); 

char* s; 

int main(int argc, char** argv) { 
    if (!(hlib = dlopen("./lib.so", RTLD_LAZY))) 
    return 1; 
    if (!(__getinfo = dlsym(hlib, "getinfo"))) 
    return 2; 
    if (__getinfo(&inf)) 
    return 3; 
    if (!(foo = inf->sym[0].addr)) 
    return 4; 
    s = foo(); 
    printf("%p => %s\n", inf->sym[0].addr, s);  
    return 0; 
}  

現在編譯它(無-nostartfiles):

gcc -I. -o lib.o -c lib.c -Wall -Werror -O3 -fPIC 
gcc -o lib.so lib.o -shared 
gcc -I. -o main.o -c main.c -Wall -Werror -O3 
gcc -o prog main.o -ldl 

這printf的一樣測試1:庫函數foo()的地址和其執行的結果。

我試圖展示如何獲取共享庫函數地址,但是我在第二次測試中正確嗎?我應該遇到一些麻煩嗎?

注意:在FreeBSD-8.2中不需要使用-ldl參數,所有的dlfcn.h例程都在libc庫中。

分別打包任何解釋。

回答

1

這看起來相當標準。你使用的唯一的東西可能會帶來一些問題,那就是你正在使用gcc屬性爲你的共享庫創建一個構造函數和析構函數。這可能不是完全可移植的;這取決於你關心的平臺。

請注意,在這種特定情況下,不需要做這些複雜的事情。您在第二個示例中從共享庫返回的信息在編譯時都是已知的,因此您可以使用該信息創建一個靜態結構,並使用dlsym檢索結構的地址,並從主程序或調用一個已知的函數來返回結構體。 (後者在某些角落情況下稍微靈活一點,但兩者都相當靈活。)

+0

非常感謝我的有用信息=) – user2168737 2013-03-18 09:41:20