views:

126

answers:

3

I have a program that depends on a shared library it expects to find deep inside a directory structure. I'd like to move that shared library out and into a better place. On OS X, this can be done with install_name_tool. I'm unable to find an equivalent for Linux.

For reference, readelf -d myprogram spits out the following paraphrased output:

Dynamic section at offset 0x1e9ed4 contains 30 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [this/is/terrible/library.so]
 0x00000001 (NEEDED)                     Shared library: [libGL.so.1]
 0x00000001 (NEEDED)                     Shared library: [libGLU.so.1]
 0x00000001 (NEEDED)                     Shared library: [libstdc++.so.6]
(continues in an uninteresting fashion)

(and by request, ldd myprogram:)

    linux-gate.so.1 =>  (0x0056a000)
    this/is/terrible/library.so => not found
    libGL.so.1 => /usr/lib/mesa/libGL.so.1 (0x0017d000)
    libGLU.so.1 => /usr/lib/libGLU.so.1 (0x00a9c000)
    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00710000)
   (etc, etc)

and I would like to errata "this/is/terrible/library.so" to be "shared/library.so". Note that, if the program is left in its "built" location, where the relative path this/is/terrible/library.so actually exists, then ldd is able to find it, as you'd expect.

I know about RPATH and it isn't what I'm looking for, I don't need to change search paths globally.

A: 

You can use LD_LIBRARY_PATH to change the search path for shared libraries. If your program depends on a particular relative path like your example shows, you will still need to have that directory structure. In other words you can move the lib from /home/user/dev/project/this/is/terrible/library.so to /usr/local/lib/this/is/terrible/library.so but not to /usr/local/lib/library.so

If you can rebuild your program, then you can change the relative path it uses for the lib.

There's some more info on shared libs in Linux at http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

JayM
Doesn't help in my case. I'm taking a program that is already built, then trying to deploy it to other people's systems. First, I don't want to muck about with LD_LIBRARY_PATH on their systems. Second, as you mention, that wouldn't actually get rid of the this/is/terrible/ prefix, only allow me to add another prefix in front of it. My program only depends on that directory structure because that's where it's looking for the DLL - that's exactly what I am attempting to change :)
ZorbaTHut
+1  A: 

Posting a tentative, horrible, hacky solution.

The library dependencies are stored in an ELF block known as the .depends block. The format of that block is a large array of identifier/stringpointer pairs, with the stringpointer pointing to a standard C null-terminated string located somewhere in the binary.

You see where this is going, right?

Yep, as long as the new path you need is no larger than the old path, you can just reach right into the binary and do a simple string replace. Make sure not to add or remove bytes or you'll break the entire binary. If you want to be safer about it, you could actually traverse the ELF structure to ensure you had the right location - right now I'm just checking to make sure the source string shows up exactly once.

ELF does include a checksum, but apparently there's no loader that actually verifies it, so it's "safe" - albeit messy - to ignore.

The "real solution" would be a utility that allowed low-level generalized manipulations of the ELF structure. As near as I can tell, no such utility exists, for anything except a few specialized cases (RPATH, mostly.) I don't pretend to know how difficult such a utility would be to write.

I would absolutely love a better solution to this, but, so far, this appears to work.

ZorbaTHut
I cringed when I thought about hex-editing ELF blocks, but I suppose it would work. If the app won't be moved once installed you can symlink "shared/library.so" and "this/is/terrible/library.so". However, I would recommend re-building with the correct paths and issuing a patch/update to users of your program as a much more user-friendly solution.
bta
The real issue with "rebuilding" is that I don't want to pollute my build system layout with weird requirements from runtime, and similarly I don't want to pollute my runtime layout with weird requirements from buildtime. It's not a compatibility issue at all, it's just making sure that both myself and my users are happy.
ZorbaTHut
I don't see how re-building your app with one more argument to CC would pollute your build environment. But I guess you should know better then me :-)
Stan
+1  A: 

HT - this might be helpful.

HT is a file editor/viewer/analyzer for executables. The goal is to combine the low-level functionality of a debugger and the usability of IDEs. We plan to implement all (hex-)editing features and support of the most important file formats.

I couldn't find something much different from ZorbaTHut's solution, but perhaps it's possible to put a name with different length and still keep the binary valid.

gelf - this could be useful too.

GElf is a generic, ELF class-independent API for manipulat- ing ELF object files. GElf provides a single, common inter- face for handling 32-bit and 64-bit ELF format object files.

Dmitry Yudakov
Nice. HT isn't practical for me because I need a CLI solution. gelf looks entirely practical - assuming it works - I'd just need to write the actual code around it. Best answer so far.
ZorbaTHut