How can I change the filename of a shared library after building a program that depends on it?
Asked Answered
O

4

28

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.

Oncoming answered 3/5, 2010 at 15:45 Comment(5)
So you're saying that path "this/is/terrible/" is not set as rpath? Is it part of the library's SONAME then? I don't think there's install_name on Linux.Immanuel
Yes, it would be part of the SONAME, introduced by the linker based off the original path when it was linked in.Oncoming
could you also post ldd ./yourprogram output?Immanuel
+1, I have a nearly identical problem that has been festering for months. Thanks for prodding me to pick the brains of some people that might be able to help.Pulsometer
This just means "your" program was built in a broken way. You should never use relative (or absolute) library paths, just add path with library to directory where ld can find it (or using -L/path/to/lib gcc option). I am not sure if you are in position to modify the program build process. If not...well..good luck.Surefire
I
6

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.

Immanuel answered 3/5, 2010 at 19:26 Comment(3)
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.Oncoming
patchelf (currently) doesn't have this feature. it just allows you to remove dependencies entirely, or set the RPATH (which is different from changing the name of one shared lib)Canaletto
@hraban: Now it is possible. Check my answerShowalter
S
32

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
Showalter answered 13/6, 2017 at 19:33 Comment(1)
patchelf has been corrupting my binaries quite often, sometimes not noticeable at first glance, but later either segfaulting, or ldconfig creating garbage-named symlinks etc.. So beware.Turnover
O
11

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.

Oncoming answered 3/5, 2010 at 17:52 Comment(5)
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.Laurielaurier
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.Oncoming
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 :-)Surefire
Consider mentioning patchelf for changing RPATH for elf binary.Ranitta
Yes it works, that's what i did in #14611640Berglund
I
6

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.

Immanuel answered 3/5, 2010 at 19:26 Comment(3)
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.Oncoming
patchelf (currently) doesn't have this feature. it just allows you to remove dependencies entirely, or set the RPATH (which is different from changing the name of one shared lib)Canaletto
@hraban: Now it is possible. Check my answerShowalter
W
-3

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

Waechter answered 3/5, 2010 at 17:36 Comment(1)
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 :)Oncoming

© 2022 - 2024 — McMap. All rights reserved.