I've seen a bunch of questions here and on other forums where the suggestion is to use -static
or sometimes even -static -static-libgcc
along with the compile arguments. This never works on Alpine, but woks fine on Ubuntu and Fedora.
I wrote a simple hello-world program in C, then had is compiled as gcc -static test.c
. And the resulting binary still lights up ldd
. See,
$ gcc -s test.c -static
$ ldd ./a.out
/lib/ld-musl-x86_64.so.1 (0x7f043eae8000)
$ file ./a.out
./a.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, stripped
Running the same on Ubuntu shows:
$ gcc -s test.c -static
$ file ./a.out
./a.out: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=bf6bfa1c78c541ae4e81586bcd050923bca9e34a, stripped
What is the correct and consistent way to static link libc itself on any platform? Is this something to do with the way GCC itself is compiled?
Statically linking libc is it's own minefield. It can and is done but even if you statically link everything else you should almost always dynamically link against your platform's libc. Statically linking libc is harder than dynamically linking it, but certainly easier than rewriting it.
libc is the C Standard library which is also linked dynamically. Let us now try to link the standard libraries statically so that our new executable a1. out does not have any runtime dependencies.
However libc has not been linked in statically, only dynamically, so it is another failed attempt.
A static library is usually identified by a . a (for "archive") suffix (e.g. libc. a). The library contains the modules you want to include in your program and is formatted as a collection of ELF object modules that the linker can then extract (as required by your program) and bind with your program at link time.
I'm answering my own question here for those who naively came here searching on keywords like static link libc
or something.
If this is for MSVC, your only option is /MT
or /MTd
. But if you came here looking for GCC, welcome to the position independent code rabbit hole.
There are several variations of GCC floating around that are patched for specific targets or patched just because they can be. So if you have, say GCC version 6.0 and expect your command line arguments to generate same behaviour, you could be a victim of some bad patch work.
Some versions of GCC as in this question enforce position independent executable (-fPIE -pie
) and silently ignore the -static
option as seen in this example. I wonder if this should be reported as a bug to Alpine maintainers. To force it to ignore PIE, pass -no-pie
to your GCC.
$ gcc -no-pie -static test.c
And if you do
$ file ./a.out
/lib/ld-musl-x86_64.so.1: ./a.out: Not a valid dynamic program
For details of how fPIE
and static
read these slides from OpenBSD.
Your Ubuntu binary isn't PIE-enabled. If you pass -no-pie
to GCC on Alpine, its binary will similarly not be PIE-enabled, but then it will be statically linked as you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With