[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: NPTL and static linking



bluujack@gmail.com said:
> I appreciate the clarification. What is desirable, then, is for the
> developer to be able to statically link his or her own libraries, and
> third party libraries, but to dynamically pick up "system" libraries,
> of which I would number libpthread. That would be adequate for my
> needs. I expect this is possible, as *everything* is possible,
> somehow. Perhaps it is something as trivial as a compiler or linker
> flag that I have missed?

I just figured out a way to do this for the ssh binary. Maybe this would
work for you?

Here's what I did:

$ apt-get source ssh
$ cd openssh-3.8.1p1
$ debian/rules build

At first, we just want to get everything built. I only want to tinker
with the final linking step.

Now, I'm interested in having a statically linked ssh, except for libc.
So I rm ssh and remake it, to see how it's linked:

$ cd build-deb
$ rm ssh
$ make ssh
(cd openbsd-compat && make)
make[1]: Entering directory `/home/lunz/openssh-3.8.1p1/build-deb/openbsd-compat'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/lunz/openssh-3.8.1p1/build-deb/openbsd-compat'
gcc -o ssh ssh.o readconf.o clientloop.o sshtty.o sshconnect.o sshconnect1.o sshconnect2.o -L. -Lopenbsd-compat/  -lssh -lopenbsd-compat -lresolv -lcrypto -lutil -lz -lnsl -lcrypt

running that gcc invocation with -v, and we get:

$ gcc -o ssh ssh.o readconf.o clientloop.o sshtty.o sshconnect.o sshconnect1.o sshconnect2.o -L. -Lopenbsd-compat/  -lssh -lopenbsd-compat -lresolv -lcrypto -lutil -lz -lnsl -lcrypt -v
Reading specs from /usr/lib/gcc-lib/i486-linux/3.3.5/specs
Configured with: ../src/configure -v --enable-languages=c,c++,java,f77,pascal,objc,ada,treelang --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-gxx-include-dir=/usr/include/c++/3.3 --enable-shared --with-system-zlib --enable-nls --without-included-gettext --enable-__cxa_atexit --enable-clocale=gnu --enable-debug --enable-java-gc=boehm --enable-java-awt=xlib --enable-objc-gc i486-linux
Thread model: posix
gcc version 3.3.5 (Debian 1:3.3.5-8)
 /usr/lib/gcc-lib/i486-linux/3.3.5/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o ssh /usr/lib/gcc-lib/i486-linux/3.3.5/../../../crt1.o /usr/lib/gcc-lib/i486-linux/3.3.5/../../../crti.o /usr/lib/gcc-lib/i486-linux/3.3.5/crtbegin.o -L. -Lopenbsd-compat/ -L/usr/lib/gcc-lib/i486-linux/3.3.5 -L/usr/lib/gcc-lib/i486-linux/3.3.5/../../.. ssh.o readconf.o clientloop.o sshtty.o sshconnect.o sshconnect1.o sshconnect2.o -lssh -lopenbsd-compat -lresolv -lcrypto -lutil -lz -lnsl -lcrypt -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc-lib/i486-linux/3.3.5/crtend.o /usr/lib/gcc-lib/i486-linux/3.3.5/../../../crtn.o

So we see how gcc calls its collect2. Calling _that_ with -v shows the
linker invocation:

$ /usr/lib/gcc-lib/i486-linux/3.3.5/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o ssh /usr/lib/gcc-lib/i486-linux/3.3.5/../../../crt1.o /usr/lib/gcc-lib/i486-linux/3.3.5/../../../crti.o /usr/lib/gcc-lib/i486-linux/3.3.5/crtbegin.o -L. -Lopenbsd-compat/ -L/usr/lib/gcc-lib/i486-linux/3.3.5 -L/usr/lib/gcc-lib/i486-linux/3.3.5/../../.. ssh.o readconf.o clientloop.o sshtty.o sshconnect.o sshconnect1.o sshconnect2.o -lssh -lopenbsd-compat -lresolv -lcrypto -lutil -lz -lnsl -lcrypt -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc-lib/i486-linux/3.3.5/crtend.o /usr/lib/gcc-lib/i486-linux/3.3.5/../../../crtn.o -v
collect2 version 3.3.5 (Debian 1:3.3.5-8) (i386 Linux/ELF)
/usr/bin/ld --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o ssh /usr/lib/gcc-lib/i486-linux/3.3.5/../../../crt1.o /usr/lib/gcc-lib/i486-linux/3.3.5/../../../crti.o /usr/lib/gcc-lib/i486-linux/3.3.5/crtbegin.o -L. -Lopenbsd-compat/ -L/usr/lib/gcc-lib/i486-linux/3.3.5 -L/usr/lib/gcc-lib/i486-linux/3.3.5/../../.. ssh.o readconf.o clientloop.o sshtty.o sshconnect.o sshconnect1.o sshconnect2.o -lssh -lopenbsd-compat -lresolv -lcrypto -lutil -lz -lnsl -lcrypt -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc-lib/i486-linux/3.3.5/crtend.o /usr/lib/gcc-lib/i486-linux/3.3.5/../../../crtn.o -v

OK, so we can see how ssh really gets linked. At this point, I want to
split the link into two steps: An initial static link that pulls
everything in, and a final link to create a dynamic elf executable
linked against libc. The ld option for incremental linking is -r. So I
try stripping out everything related to gcc, libc, the dynamic linker,
and creating elf output, and add -static:

ld -r -static -o static.o -L. -Lopenbsd-compat/ ssh.o readconf.o clientloop.o sshtty.o sshconnect.o sshconnect1.o sshconnect2.o -lssh -lopenbsd-compat -lresolv -lcrypto -lutil -lz -lnsl -lcrypt 

This gives a file, static.o, where hopefully everything's linked in,
except glibc and whatever gcc stub stuff is needed to make a working
executable.

$ ls -l static.o
-rw-r--r--  1 lunz users 5243328 2005-03-09 14:47 static.o
$ file static.o
static.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not

Finally, I do a normal link to make a regular executable:

$ gcc -o ssh static.o
$ ls -l ssh
-rwxr-xr-x  1 lunz users 2849708 2005-03-09 14:49 ssh
$ ./ssh -V
OpenSSH_3.8.1p1 Debian-8.sarge.4, OpenSSL 0.9.7e 25 Oct 2004
$ ldd ssh
        libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7eaa000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xb7fea000)

So it looks to me like a mostly-static ssh. It seems to work on all the
glibc 2.3 systems I can find, and claims to have openssl 0.9.7.

Is there anything wrong with doing this? I have by doubts that this is
completely foolproof. Any libc macros or inlines will come from the
build system's libc, for example. I don't know if that can cause
problems when a different glibc version is dynamically linked at
runtime.

Jason



Reply to: