4

我正在尝试在 C 中编写一种调度函数,它应该接收一个由函数名称组成的字符串,然后从调度函数内部调用在接收到的参数中指定名称的函数。重点是我不想在动态加载的库中定义函数。流程应该是这样的。

文件1.c

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

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

文件2.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

请注意,此方法需要完整的符号表。为了减少开销,您可以在初始化例程中重复使用上面的代码。在那里,您将存储从函数名称到地址的映射。这导致生成查找表的一次性成本。

于 2012-04-23T13:11:12.053 回答
0

你当然可以这样做:

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

和你相处得很好;在过去,许多语言解释器都是以这种方式建造的。

至于做一些更动态的事情:静态链接库根本不存在必要的运行时结构。无论你做什么,你都必须手动或自动创建某种调度表(就像我在这里展示的那样)——但你必须自己做。

于 2012-04-23T11:35:55.910 回答
0

也许您正在寻找以下类型的解决方案:

文件1.c:

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

工具.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 );

文件2.c:

static void mydispatch( void )
{
...
}    

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

在该解决方案中,当您添加功能时,您不需要再次编译旧文件。只需编译新文件并链接。

于 2012-04-23T12:48:41.657 回答