2013-03-14 18 views
5

質問はどのように共有ライブラリ(UNIX/LINUX)から関数アドレスを取得できますか?共有ライブラリからの関数ポインタの取得の違い

私はUbuntu 10.04(amd64)とFreeBSD-8.2(amd64)でコンパイルして実行するCでいくつかのテストケースを書きました(下記参照)。私は何の違いも感じなかったが、私は起こりうるトラブルについてもっと知りたい。ここで

彼らは以下のとおりです。

  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のアドレス()とその実行結果。

私はどのように共有ライブラリ関数のアドレスを取得することができますが、私は2番目のテストで正しいですか?私はそれにいくつかの問題がありますか?

注:FreeBSD-8.2では、-ldl引数を使用する必要はありません。すべてのdlfcn.hルーチンはlibcライブラリにあります。

説明のためにそれぞれ対応しています。

答えて

1

これは私にとってかなり標準的です。あなたが使用している唯一の問題は、gcc属性を使って共有ライブラリのコンストラクタとデストラクタを作成していることです。それは完全に移植可能ではないかもしれません。あなたが気にしているプラ​​ットフォームによって異なります。

この特定のケースでは、このような複雑な作業を行う必要はありません。 2番目の例の共有ライブラリから返される情報はすべてコンパイル時にわかります。その情報で静的構造体を作成し、構造体のアドレスをdlsymで取り出し、メインプログラムを呼び出すか、構造体を返すための既知の関数を呼び出します。 (後者はいくつかのコーナーケースではやや柔軟性がありますが、どちらもかなり柔軟です。)

+0

ありがとうございました。私には有益な情報がありました=) – user2168737

関連する問題