How to Change the Soname of a Binary Directly

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

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.

What is the 'soname' option for building shared libraries for?

soname is used to indicate what binary api compatibility your library support.

SONAME is used at compilation time by linker to determine from the library file what actual target library version. gcc -lNAME will seek for libNAME.so link or file then capture its SONAME that will certainly be more specific ( ex libnuke.so links to libnuke.so.0.1.4 that contains SONAME libnuke.so.0 ).

At run time it will link with this is then set into ELF dynamic section NEEDED, then a library with this name ( or a link to it ) should exists.
At Run time SONAME is disregarded, so only the link or the file existence is enough.

Remark: SONAME is enforced only at link/build time and not at run time.

'SONAME' of library can be seen with 'objdump -p file |grep SONAME'.
'NEEDED' of binaries can be seen with 'objdump -p file |grep NEEDED'.

[EDIT] WARNING Following is a general remark, not the one deployed in linux. See at the end.

Let's assume you have a library with libnuke.so.1.2 name and you develop a new libnuke library :

  • if your new library is a fix from previous without api change, you should just keep same soname, increase the version of filename. ie file will be libnuke.so.1.2.1 but soname will still be libnuke.so.1.2.
  • if you have a new library that only added new function but didn't break functionality and is still compatible with previous you would like to use same soname than previous plus a new suffix like .1. ie file and soname will be libnuke.so.1.2.1. Any program linked with libnuke.1.2 will still work with that one. New programs linked with libnuke.1.2.1 will only work with that one ( until new subversion come like libnuke.1.2.1.1 ).
  • if your new library is not compatible with any libnuke : libnuke.so.2
  • if your new library is compatible with bare old version : libnuke.so.1.3 [ ie still compatible with libnuke.so.1 ]

[EDIT] to complete : linux case.

In linux real life SONAME as a specific form :
lib[NAME][API-VERSION].so.[major-version]
major-version is only one integer value that increase at each major library change.
API-VERSION is empty by default

ex libnuke.so.0

Then real filename include minor versions and subversions ex : libnuke.so.0.1.5

I think that not providing a soname is a bad practice since renaming of file will change its behavior.

Change Linux shared library (.so file) version after it was compiled

Discussion with Slava made me realize that any const char* was actually visible in the binary file and could then be easily patched to anything else.

So here is a nice way to fix my own problem:

  1. Create a library with:

    • a definition of const char version[] = "VERSIONSTRING:00000.00000.00000.00000"; (we need it long enough as we can later safely modify the binary file content but not extend it...)
    • a GetVersion function that would clean the version variable above (remove VERSIONSTRING: and useless 0). It would return:

      • 0.0 if version is VERSIONSTRING:00000.00000.00000.00000
      • 2.3 if version is VERSIONSTRING:00002.00003.00000.00000
      • 2.3.40 if version is VERSIONSTRING:00002.00003.00040.00000
      • ...
  2. Compile the library, let's name it mylib.so
  3. Load it from a program, ask its version (call GetVersion), it returns 0.0, no surprise
  4. Create a little program (did it in C++, but could be done in Python or any other languauge) that will:

    • load a whole binary file content in memory (using std::fstream with std::ios_base::binary)
    • find VERSIONSTRING:00000.00000.00000.00000 in it
    • confirms it appears once only (to be sure we don't modify something we did not mean to, that's why I prefix the string with VERSIONSTRING, to make it more unic...)
    • patch it to VERSIONSTRING:00002.00003.00040.00000 if expected binary number is 2.3.40
    • save the binary file back from patched content
  5. Patch mylib.so using the above tool (requesting version 2.3 for instance)
  6. Run the same program as step 3., it now reports 2.3!

No recompilation nor linking, you patched the binary version!

forcing linking with a different SONAME than this of library

patchelf is your friend. You can do something like: patchelf --replace-needed libcapi10.so.3 libcapi10.so.4 <your_thing>.

Patchelf is useful for a variety of other things such as changing RPATH, too. Check out the manpage. Very nifty toy.

Can I change 'rpath' in an already compiled binary?

There is a tool called chrpath which can do this - it's probably available in your distribution's packages.

How to change the name of the output binary to not be a.out with CMake?

Here's a simple CMakeLists.txt

cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
project(demo)

add_executable(hello hello.cpp)

This CMakeLists.txt compiles a hello.cpp file to an executable named hello. You can name the executable anything by using the add_executable statement.

add_executable(<executable-name> <source1> <source2> ...)

How can I change the binary file link to something else

The command run when you type python is determined primarily by the setting of your $PATH. The first executable file called python that is found in a directory listed on your $PATH will be the one executed. There is no 'link' per se. The which command will tell you what the shell executes when you type python.

If you want python to open a different program, there are a number of ways to do it. If you have $HOME/bin on your $PATH ahead of /usr/bin, then you can create a symlink:

ln -s /usr/bal/bla/python2.7 $HOME/bin/python

This will now be executed instead of /usr/bin/python. Alternatively, you can create an alias:

alias python=/usr/bal/bla/python2.7

Alternatively again, if /usr/bal/bla contains other useful programs, you could add /usr/bal/bla to your $PATH ahead of /usr/bin.

There are other mechanisms too, but one of these is likely to be the one you use. I'd most probably use the symlink in $HOME/bin.



Related Topics



Leave a reply



Submit