I have a legacy system with a very old glibc, which we can't upgrade without incurring a mountain of testing/validation work.

I have needed to run newer programs (such as Java 1.7) on that system several times now. I opted for a chroot solution, where I package up all the needed libs, and run a service in a chroot.

The chroot is very limiting though, and I'd rather try to solve the problem with LD_LIBRARY_PATH. Unfortunately, I get an error about libc.so.6: cannot handle TLS data when I try that.

It turns out I need the /lib/ld-linux.so.2 from the chroot as well. This works:

LD_LIBRARY_PATH=/home/chroot/lib /home/chroot/lib/ld-linux.so.2 /home/chroot/bin/program

However, java foils my trick by inspecting /proc/self/cmdline to determine where to load its libraries from, which fails if the binary wasn't named 'bin/java'. Also java execs itself during startup, further complicating matters.

In a last-ditch attempt to make this work, I opened the java binary with a hex editor and replaced the string /lib/ld-linux.so.2 with /home/chroot/ld.so (and made that a symlink to ld-linux.so.2), and it worked!

But I think everyone would agree that it is a massive kludge to rewrite the path of every new binary to an absolute path of the nested system.

Does anyone know a cleaner way to use a custom library path including a custom ld-linux.so?


The path to the loader is compiled into the binary as you discovered with your hex editor. You actually got lucky that editing the binary directly worked because both /lib/ld-linux.so.2 and /home/chroot/ld.so are the same length. The lengths of those strings are also in the binary and you can cause subtle problems if you modify the strings directly.

If you end up going the route you should take a look at some thing like patchelf to update the interpreter. This would let you permanently change the interpreter quickly and safely.

  • Wasn't luck, I knew I needed to not shift any of the bytes ;-) But, patchelf looks like just what I want. Aside from not being able to use a relative path, it can also take care of the LD_LIBRARY_PATH I'm using so that I don't need a wrapper. I'll give you credit for the answer as soon as I get a chance to test it.
    – dataless
    Apr 5 '14 at 5:55
  • 1
    It works! This will give me a decent path forward to mix new-libc programs with the old-libc programs on this server. For future readers, the command was patchelf --set-interpreter $JAVA/lib/ld-linux.so.2 --set-rpath $JAVA/lib:$JAVA/lib/i386:$JAVA/lib/i386/jli $JAVA/bin/java, where $JAVA is the directory of the JRE, and where I had rounded up all dependent libraries and put them in the lib/ directory of the JRE.
    – dataless
    Apr 7 '14 at 19:41
  • @dataless well I still need LD_LIBRARY_PATH to workaround this libjvm.so, because libstdc++.so.6: cannot open shared object file: No such file or directory [root@97245bbe7cc1 tensorflow-java]#
    – Amos
    Aug 6 '18 at 22:36
  • @Amos It's been a while, but for my case I did not need LD_LIBRARY_PATH anymore because the default comes from the java binary. But, note the part where I said that I went around and found all libs used by java and copied them into the java lib dir. I used ldd $JAVA/bin/java to get the ist. There are also some dynamic libc ones you need like libnss.so
    – dataless
    Aug 8 '18 at 17:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.