0

I'm writing a program in C which allows users to implement custom "functions" to be run by an interpreter of sorts. I also want to allow users to write these custom functions in plain C, and then be loaded in dynamically. In order to do this, I created two structs, one for interpreted functions, and one for native ones.

Here's a simplified example:

struct func_lang {
    bool is_native;
    char* identifier;
    // various other properties
}

typedef void (*func_native_ptr)(int);
struct func_native {
    bool is_native;
    char* identifier;
    func_native_ptr func_ptr;
}

I then use the identifier property of each struct to put them in a hashtable, which I can then use to execute them at runtime.

My problem is actually from the other end, the loaded libraries. I'd like to be able to allow the loaded libraries to "publish" which functions they want inserted into the list. For example, maybe with a function like this:

void register_func_native(char* identifer, func_native_ptr func_ptr);

Then, when I would call an init function from the library, they could call this function to insert the functions into the hashtable.

Will this work? I'm a little confused about how the register_func_native function would be linked, since it's needed by the loaded library, but would have to be defined by the loader itself. Does my loader function need to be implemented in another shared library, which could then be linked at runtime?

Alexis King
  • 43,109
  • 15
  • 131
  • 205
  • 2
    Pass a pointer to the register function as an argument to the library's init function. – Michael Burr Jan 15 '13 at 21:09
  • Other approach might be to let the library implement a `get_native_functions()`-API, which let's you enumerate all functions provided by the library. – lethal-guitar Jan 15 '13 at 21:13
  • Calling unknown functions is problematic for other reasons also. The library would have to indicate what the function prototype looks like somehow. That is *very* far from straight-forward, so I'd recommend that your library support only functions that conform to a restricted set of function pointer types, and it should then register which signature each function uses. – ams Jan 15 '13 at 22:32
  • If you want to support call *arbitrary* function prototypes then look at using `libffi`, but even that has its limitations. – ams Jan 15 '13 at 22:34

2 Answers2

2

It will work. The shared library sees all the global symbols you have in your main program.

In the main program you'll need dlopen() and dlsym() to call the initialization function.

Kalle Pokki
  • 4,939
  • 2
  • 17
  • 18
2

This will depend on the platform, but on Linux and all the Unixes I've seen, this will work. Example:

$ cat dll.c
void print(char const *);

void foo()
{
    print("Hello!");
}
$ gcc -Wall -shared -fPIC -o dll.so dll.c
$ cat main.c
#include <dlfcn.h>
#include <stdio.h>

void print(char const *msg)
{
    puts(msg);
}

int main()
{
    void *lib = dlopen("./dll.so", RTLD_NOW);
    void (*foo)() = (void (*)())dlsym(lib, "foo");
    foo();
    return 0;
}
$ cc -fPIC -rdynamic main.c -ldl
$ ./a.out 
Hello!
Fred Foo
  • 355,277
  • 75
  • 744
  • 836