2

I have 2 files:

foo.c:

#include <stdio.h>
int Main(int a) {
    printf("A%dB",a);
}
int main() {
    return Main(1);
}

bar.c:

extern int Main(int);
int main() {
   return Main(2);
}

If I compile foo.c into an executable (gcc -fPIC foo.c -o foo.out) and run it, it correcty prints A1B.

Same for compiling foo.c into a shared object file (gcc -shared -fPIC foo.c -o libfoo.so) and bar.c into an executable that loads libfoo.so (gcc bar.c -L. -lfoo -o bar.out) and run it, it correctly prints A2B.

But if I try to (1) link bar.out with foo.out or (2) execute libfoo.so it (1) doesn't link (/usr/bin/ld: cannot use executable file './libfoo .so' as input to a link) or (2) crashes on startup with Segmentation fault (core dumped)

Is there a way to create a file that can be executed and is a valid shared object file at the same file, and if not, are there other ways to load the a.out executable (maybe some kind of a dlopen hack) from b.out to run a function from a.out

I am also interested if there is a way to load the executable using java's System.loadLibrary("native") (if possible, only changing the c side and not the java side)

FYI, I want to do this, so I can have an android executable that can be run from something like termux while also being able to be loaded from Android.jar to run as a standalone GUI app

3

1 Answer 1

4

To allow foo.out to be used as both an executable and as a library, you first need to compile it with -FPIE and -pie to allow it to be read via dlopen as well as -rdynamic to export the symbols it contains:

gcc -fPIE -pie -rdynamic foo.c -o foo.out

Then update bar.c to use dlopen and dlsym:

#include <stdio.h>
#include <dlfcn.h>

int main() {
    void *lib = dlopen("./foo.out",RTLD_LAZY);
    if (!lib) {
        printf("dlopen failed: %s\n", dlerror());
        return 1;
    }

    int (*Main)(int) = dlsym(lib,"Main");
    if (!Main) {
        printf("dlsym failed: %s\n", dlerror());
        return 1;
    }

    return Main(2);
}

And link with libdl:

gcc bar.c  -o bar.out -ldl

Then you'll get the expected results:

[dbush@db-centos7 ~]$ ./bar.out
A2B[dbush@db-centos7 ~]$ 
Sign up to request clarification or add additional context in comments.

4 Comments

This was explicitly disabled back in 2019 in glibc-2.30.
If so, is there another way to do that (Is it dlopen's implementation that got changed, or is it internally not doable with linux)?
Look at my comment under the main question.
I tried it and running b.out failed with dlopen failed: ./a.out: cannot dynamically load position-independent executable

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.