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.
The -shared or -dynamiclib option is required to create a shared library. The name of the source file is octagon.
A shared library or shared object is a file that is intended to be shared by multiple programs. Symbols used by a program are loaded from shared libraries into memory at load time or runtime.
If you want to open a shared-library file, you would open it like any other binary file -- with a hex-editor (also called a binary-editor). There are several hex-editors in the standard repositories such as GHex (https://packages.ubuntu.com/xenial/ghex) or Bless (https://packages.ubuntu.com/xenial/bless).
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With