How can I change the filename of a shared library

2019-01-21 11:56发布

问题:

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.

回答1:

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.



回答2:

We can use patchelf:

patchelf --replace-needed liboriginal.so.1 libreplacement.so.1 my-program

We can also remove a dependency:

patchelf --remove-needed libfoo.so.1 my-program

Add a dependency:

patchelf --add-needed libfoo.so.1 my-program

Or change the path where to search for the libraries (rpath):

patchelf --set-rpath /path/to/lib:/other/path my-program


回答3:

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.



回答4:

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