building a .so that is also an executable

Update 2: see Andrew G Morgan’s slightly more complicated solution which does work for any GLIBC (that solution is also used in libc.so.6 itself (since forever), which is why you can run it as ./libc.so.6 (it prints version info when invoked that way)).

Update 1: this no longer works with newer GLIBC versions:

./a.out: error while loading shared libraries: ./pie.so: cannot dynamically load position-independent executable

Original answer from 2009:

Building your shared library with -pie option appears to give you everything you want:

/* pie.c */
#include <stdio.h>
int foo()
{
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return 42; 
}
int main() 
{ 
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return foo(); 
}


/* main.c */
#include <stdio.h>

extern int foo(void);
int main() 
{ 
  printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
  return foo(); 
}


$ gcc -fPIC -pie -o pie.so pie.c -Wl,-E
$ gcc main.c ./pie.so


$ ./pie.so
in main pie.c:9
in foo pie.c:4
$ ./a.out
in main main.c:6
in foo pie.c:4
$

P.S. glibc implements write(3) via system call because it doesn’t have anywhere else to call (it is the lowest level already). This has nothing to do with being able to execute libc.so.6.

Leave a Comment