4

関数名で構成される文字列を受け取るようなディスパッチ関数をCで記述し、その後、ディスパッチ関数内から、受け取った引数で名前が指定されている関数を呼び出せるようにしようとしています。要点は、動的にロードされたライブラリで関数を定義したくないということです。フローは次のようになります。

file1.c

void hello()
{
   fprintf(stderr,"Hello world\n");
}

void myfunc()
{
   mydispatch("hello");
}

file2.c

void mydispatch(const char *function)
{
...
}

この構造はちょっと変かもしれませんが、私は主にこれができるかどうか疑問に思っていました。

4

3 に答える 3

3

BFD を使用して、実行時にシンボル名からアドレスを取得できます。

#include <stdio.h>
#include <stdlib.h>
#include <bfd.h>
#include <string.h>

void func1(int n)
{
    printf("%d\n", n);
}

void * addr_from_name(char * filename, char * symname)
{
    bfd *        ibfd;
    asymbol **   symtab;
    symbol_info  info;
    void *       symaddress = NULL;
    long         size;
    long         syms;
    unsigned int i;

    bfd_init();

    ibfd = bfd_openr(filename, NULL);
    bfd_check_format(ibfd, bfd_object);

    size   = bfd_get_symtab_upper_bound(ibfd);
    symtab = malloc(size);
    syms   = bfd_canonicalize_symtab(ibfd, symtab);

    for(i = 0; i < syms; i++) {
        if(strcmp(symtab[i]->name, symname) == 0) {
            bfd_symbol_info(symtab[i], &info);
            symaddress = (void *)info.value;
        }
    }

    bfd_close(ibfd);
    return symaddress;
}

int main(void)
{
    void (*func)(int) = addr_from_name("/homes/mk08/Desktop/lala", "func1");
    printf("%p\n", func);
    func(5);
    return EXIT_SUCCESS;
}

この場合、ハードコーディングfilenameしましたが、動的に取得するのは簡単です。ソース/バイナリが と呼ばれていると仮定するとlala、次のようにコンパイルして実行できます。

gcc -Wall -std=gnu99 lala.c -o lala -lbfd && ./lala

私のシステムでは、これは次のように出力されます。

0x400814
5

このメソッドには、元のシンボル テーブルが必要であることに注意してください。オーバーヘッドを減らすために、初期化ルーチンで上記のコードを再利用できます。そこに、関数名からアドレスへのマッピングを保存します。これにより、ルックアップ テーブルを生成するための 1 回限りのコストが発生します。

于 2012-04-23T13:11:12.053 に答える
0

たぶん、あなたは次の種類の解決策を探しています:

file1.c:

void myfunc()
{
   my_function_type fun = search_function( "operation1" );
   fun(); 
}

tools.h:

typedef void (*my_function_type)( void );
void register_function( my_function_type fp, const char* name );
my_function_type search_function( const char* name );

file2.c:

static void mydispatch( void )
{
...
}    

static void __attribute__ ((constructor)) register_functions()
{
     register_function( mydispatch, "operation1" );
}

そのソリューションでは、機能を追加するときに古いファイルを再度コンパイルする必要はありません。新しいファイルとリンクをコンパイルするだけです。

于 2012-04-23T12:48:41.657 に答える
0

あなたは確かに次のようにすることができます:

void mydispatch(const char *function)
{
    if (!strcmp(function, "hello")
        hello();
    else if (!strcmp(function, "goodbye")
        goodbye();
}

そして、あなたは良い仲間になるでしょう。多くの言語通訳者は、昔はこのように構築されていました。

より動的なことを行う限り、必要なランタイム構造は静的にリンクされたライブラリにはありません。何をするにしても、(ここで示したような) ある種のディスパッチ テーブルを手動または自動で作成する必要がありますが、自分で作成する必要があります。

于 2012-04-23T11:35:55.910 に答える