skyel
skyel

Reputation: 763

dlsym-like behaviour for static linked libraries

I am trying to write sort of a dispatch function in C that should receive a string consisting of a function name, and afterwards from inside the dispatch function to be able to call the function whose name is specified in the argument received. The whole point is that I do not want to define the function in a dynamically loaded library. The flow should be something like this.

file1.c

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

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

file2.c

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

I know this structure may be sort of weird, but I was mainly wondering if one could do this.

Upvotes: 4

Views: 1170

Answers (3)

Mike Kwan
Mike Kwan

Reputation: 24447

You can use BFD to get the addresses at runtime from symbol names.

#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;
}

In this case, I hardcoded filename, but it is trivial to get it dynamically. Assuming your source/binary is called lala, you can compile and run like so:

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

On my system, this prints:

0x400814
5

Note that this method requires an intact symbol table. To reduce overhead, you can re-use the code above in an initialisation routine. In there, you would store a mapping from function names to addresses. This results in a one-off cost for generating a lookup table.

Upvotes: 3

SKi
SKi

Reputation: 8476

Maybe you are seaching the following kind of solution:

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" );
}

In that solution you don't need to compile old files again, when you add functionality. Just compile the new file and link.

Upvotes: 0

Ernest Friedman-Hill
Ernest Friedman-Hill

Reputation: 81704

You can certainly do it like this:

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

and you'd be in good company; many a language interpreter was built this way in the olden times.

As far as doing something more dynamic: the necessary runtime structures simply aren't there for statically-linked libraries. Whatever you do, you're going to have to create some kind of dispatch table (like what I've shown here) manually or automatically -- but you're going to have to do it yourself.

Upvotes: 0

Related Questions