Last update: 26-Mar-2021
Author: R. Koucha
How to make executable shared libraries
Introduction
Example of shared library
Making an executable shared library
References
About the author
Introduction

You may know that it is possible to run the C shared library. For example, on my Linux system, if I run it, it displays its version:

$ /lib/libc.so.6
GNU C Library (Ubuntu EGLIBC 2.11.1-0ubuntu7.8) stable release version 2.11.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.3.
Compiled on a Linux >>2.6.24-27-server<< system on 2011-01-21.
Available extensions:
        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
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.

This paper focuses on the recipe to make executable shared libraries.

Example of shared library

Here is the source file of a shared library:

service.c
#include <stdio.h>

void lib_service(void)
{

  printf("This is a service of the shared library\n");

} // lib_service

Here is a main program which uses the preceding shared library:

main.c
#include <stdio.h>

extern void lib_service(void);

int main(int ac, char *av[])
{

  lib_service();

  return 0;
} // main

To build this program along with its shared library, we do:

$ gcc -shared service.c -o libservice.so -Wl,-soname,libservice.so
$ gcc main.c -o main -lservice -L.

To run the program we do:

$ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:`pwd`
$ ./main
This is a service of the shared library

If we run the library we get a segmentation fault:

$ chmod +x ./libservice.so
$ ./libservice.so
Erreur de segmentation
Making an executable shared library

We must first specify an entry point for the library:


service.c
#include <stdio.h>

void lib_service(void)
{

  printf("This is a service of the shared library\n");

} // lib_service


void lib_entry(void)
{
  printf("Entry point of the service library\n");
}

This entry point is set into the object thanks to the "-e" option of the linker:

$ gcc -shared service.c -o libservice.so -Wl,-soname,libservice.so -Wl,-e,lib_entry

But the execution still fails:

$ ./libservice.so
Illegal instruction

We must make the entry point be a "no return" function thanks to the "_exit()" service:

service.c
#include <stdio.h>
#include <unistd.h>

void lib_service(void)
{

  printf("This is a service of the shared library\n");

} // lib_service


void lib_entry(void)
{
  printf("Entry point of the service library\n");

  _exit(0);
}

But the execution still fails:

$ gcc -shared service.c -o libservice.so -Wl,-soname,libservice.so -Wl,-e,lib_entry
$ ./libservice.so
Illegal instruction

We specify the interpreter file to be the dynamic linker. On our Linux system, it is /lib/ld-linux.so.2. Make sure to use the right linker. If the system is 64 bits, this may be something like: /lib64/ld-linux-x86-64.so.2.

service.c
#include <stdio.h>
#include <unistd.h>


const char service_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";

void lib_service(void)
{

  printf("This is a service of the shared library\n");

} // lib_service


void lib_entry(void)
{
  printf("Entry point of the service library\n");

  _exit(0);
}

Now it works !

$ gcc -shared service.c -o libservice.so -Wl,-soname,libservice.so -Wl,-e,lib_entry
$ ./libservice.so
Entry point of the service library

Although, it is executable, the file is still usable as a library since the "main" executable can still dynamically link with it:

$ ./main
This is a service of the shared library

If the linker pathname is not correct, an error like the following may be displayed:

$ ./libservice.so
bash: ./libservice.so: Accessing a corrupted shared library

NB: If you are using the G++ compiler, make sure that the entry point is defined as a C language symbol with the extern "C" directive. For example:

service.c
#include <stdio.h>
#include <unistd.h>


const char service_interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";

void lib_service(void)
{

  printf("This is a service of the shared library\n");

} // lib_service


extern "C" {

void lib_entry(void)
{
  printf("Entry point of the service library\n");

  _exit(0);
}

}
References

About the author

The author is an engineer in computer sciences located in France. He can be contacted here.