Linux Executables – Why Some Shared Libraries Are Runnable

executableglibclinuxshared libraryversion

On 32-bit Linux systems, invoking this

$ /lib/libc.so.6

and on 64-bit systems this

$ /lib/x86_64-linux-gnu/libc.so.6

in a shell, provides an output like this:

GNU C Library stable release version 2.10.1, by Roland McGrath et al.
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.4.0 20090506 (Red Hat 4.4.0-4).
Compiled on a Linux >>2.6.18-128.4.1.el5<< system on 2009-08-19.
Available extensions:
    The C stubs add-on version 2.1.2.
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
    RT using linux kernel aio
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.

Why and how does this happen, and how is it possible to do the same in other shared libraries?

I looked at /usr/lib to find executables, and I found /usr/lib/libvlc.so.5.5.0. Running it led to a segmentation fault. :-/

Best Answer

That library has a main() function or equivalent entry point, and was compiled in such a way that it is useful both as an executable and as a shared object.

Here's one suggestion about how to do this, although it does not work for me.

Here's another in an answer to a similar question on S.O, which I'll shamelessly plagiarize, tweak, and add a bit of explanation.

First, source for our example library, test.c:

#include <stdio.h>                  

void sayHello (char *tag) {         
    printf("%s: Hello!\n", tag);    
}                                   

int main (int argc, char *argv[]) { 
    sayHello(argv[0]);              
    return 0;                       
}                   

Compile that:

gcc -fPIC -pie -o libtest.so test.c -Wl,-E

Here, we are compiling a shared library (-fPIC), but telling the linker that it's a regular executable (-pie), and to make its symbol table exportable (-Wl,-E), such that it can be usefully linked against.

And, although file will say it's a shared object, it does work as an executable:

> ./libtest.so 
./libtest.so: Hello!

Now we need to see if it can really be dynamically linked. An example program, program.c:

#include <stdio.h>

extern void sayHello (char*);

int main (int argc, char *argv[]) {
    puts("Test program.");
    sayHello(argv[0]);
    return 0;
}

Using extern saves us having to create a header. Now compile that:

gcc program.c -L. -ltest

Before we can execute it, we need to add the path of libtest.so for the dynamic loader:

export LD_LIBRARY_PATH=./

Now:

> ./a.out
Test program.
./a.out: Hello!

And ldd a.out will show the linkage to libtest.so.

Note that I doubt this is how glibc is actually compiled, since it is probably not as portable as glibc itself (see man gcc with regard to the -fPIC and -pie switches), but it demonstrates the basic mechanism. For the real details you'd have to look at the source makefile.

Related Question