Reputation: 938
I've seen some versions of libc.so which, when executed from the command line, will print a version string, like so:
$ /lib/libc.so.6
GNU C Library (Buildrood) stable release version 2.30.
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTIBILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.4.0.
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<https://www.gnu.org/software/libc/bugs.html>.
There's obviously some kind of entry point into this library, while still preserving main()
for user programs.
I'd like to do this for my own library, to print useful information about how it was compiled, what it supports etc. My searches regarding this have not been fruitful, but perhaps I'm searching the wrong thing. How can I do this?
Upvotes: 1
Views: 634
Reputation:
Position independent executables (PIE) are now the default on systems like Linux and OpenBSD [1]. So you can just build your shared library as you would a regular executable, and give the executable as an object argument to cc
, LD_PRELOAD
or dlopen()
it as if it were a shared library.
The only thing you should make sure is that all the needed symbols are exported, which is NOT the default. So you should either use -Wl,-E
(which would and cause it to export all symbols), or give it a list of exported symbols via -Wl,--dynamic-list=filename
.
$ cc -Wl,--dynamic-list=<(echo '{func;};') -include stdio.h -o shared.so -xc - <<'EOT'
int main(){ printf("Shared library!\n"); }
void func(){ printf("Exported function!\n"); }
EOT
$ cc -include stdio.h -xc - -x none ./shared.so -o main <<'EOT'
int main(){ extern void func(void); func(); }
EOT
$ ./shared.so
Shared library!
$ ./main
Exported function!
The problem with -Wl,-E
is that it will also export the symbols from the crt*.o
startup files, which may cause the "main" executable to reference them instead of pulling its own copy of the startup code. That doesn't look like a good idea.
A solution which would allow you to still use -Wl,-E
instead of listing all the exported symbols would be to use -Wl,--version-script=file
with a version script which localizes main
, __libc_csu*
, _start
and the rest of the zoo:
cc -Wl,-E -Wl,--version-script=<(echo '{local:_*;data_start;main;};') -include stdio.h -o shared.so -xc - <<'EOT'
int main(){ printf("Shared library!\n"); }
void func(){ printf("Exported function!\n"); }
EOT
$ ./main
Exported function!
[1] on some systems like FreeBSD or NetBSD you still have to use -pie -fPIE
in order to build a PIE executable, but not to link against one.
Upvotes: 2