Search code examples
clinuxelfdlopendynamic-library

How to compile ELF binary so that it can be loaded as dynamic library?


This is theoretical question. I am aware that perhaps best practice would be the use of shared libraries. But I ran into this question and cannot seem to find an answer anywhere.

How to construct the code and compile in ELF format a program in C/C++ so that it can be loaded with dlopen()?

For example if one executable contains implementation of some function int test() and I would like to call this function from my program (and preferably get the result of function), if that is even possible, how would I go about doing that?

In pseudocode I could describe it as follows:

ELF executable source:

void main() {
    int i = test();
    printf("Returned: %d", i);//Prints "Returned: 5"
}

int test() {
    return 5;
}

External program:

// ... Somehow load executable from above
void main() {
    int i = test();
    printf("Returned: %d", i);//Must print "Returned: 5"
}

Solution

  • Based on links provided in comments and other answers here is how it can be done without linking these programs compile time:

    test1.c:

    #include <stdio.h>
    
    int a(int b)
    {
      return b+1;
    }
    
    int c(int d)
    {
      return a(d)+1;
    }
    
    int main()
    {
      int b = a(3);
      printf("Calling a(3) gave %d \n", b);
      int d = c(3);
      printf("Calling c(3) gave %d \n", d);
    }
    

    test2.c:

    #include <dlfcn.h>
    #include <stdio.h>
    
    
    int (*a_ptr)(int b);
    int (*c_ptr)(int d);
    
    int main()
    {
      void* lib=dlopen("./test1",RTLD_LAZY);
      a_ptr=dlsym(lib,"a");
      c_ptr=dlsym(lib,"c");
      int d = c_ptr(6);
      int b = a_ptr(5);
      printf("b is %d d is %d\n",b,d);
      return 0;
    }
    

    Compilation:

    $ gcc -fPIC  -pie -o test1 test1.c -Wl,-E
    $ gcc -o test2 test2.c -ldl
    

    Execution results:

    $ ./test1
    Calling a(3) gave 4 
    Calling c(3) gave 5
    $ ./test2 
    b is 6 d is 8
    

    References:

    PS: In order to avoid symbol clashes imported symbols and pointers they assigned to better have different names. See comments here.