How to Rename a Shared Library to Avoid Same-Name Conflict

How to rename a shared library to avoid same-name conflict?

Background concepts

Shared libraries are used at two points:

  • compilation by the linker (ld)
  • execution by the dynamic loader
  1. If you compile in gcc with -ljson, the basename will be stored in the executable

    On execution time, standard paths will be searched for that basename.

    At link time, the linker must be able to find your library on it's search path. It is not easy to prepend to the search path:

    • GCC how to add before the default linker search path by default? LIBRARY_PATH not working
    • How to stop gcc from passing -L with standard library paths to the linker

    You might be able to get away with /usr/local/lib which is intended for user compiled libraries and should come before /usr/lib.

    But doing so will break anything that uses the other libjson, so you likely don't want that.

  2. If you compile in gcc with -l:/full/path/to/libjson.so the full path will be stored in the executable.

    On execution, no path searching is needed since we have the full path already.

You can check which is stored in the executable with:

readelf -d a.out | grep 'Shared library'

Possible solutions

I don't see any good solution that does not require editing the Makefile of the project, so the details are project specific. But in general terms, you can either:

  1. Edit the Makefile or similar for the library, and rename the basename to libjson_mine.so.

    Compile programs that need that library with: -ljson_mine. This will work since we know that /usr/lib is in the .so search path.

    This is the best option and has to be done sooner or later, or it will be the source of endless confusion... send a pull request!

    In the same pull request, also change the default installation directory to /usr/local/lib instead of /usr/lib. That is where sane user compiled libraries must go by default, exactly to avoid overwriting distribution supplied ones.

  2. If the owner does not want to rename the library, find an option in the Makefile to change the basename of the generated library.

If such option does not exist, pull request. If the owner does not want to accept that, fork the project ;-)

Then you and your distribution can use that option when compiling.
  1. Find an option in the Makefile that changes the directory in which the library + headers are installed, then use something completely custom (~/usr/lib, ~usr/include), and add that to your dynamic loader search path How to specify preference of library path? + include search path. See DESTDIR and PREFIX of make for GNU methods.

    Then at compile / execution time, change the include / dynamic loader search paths.

    Not ideal, but might work for a one-off.

What should I do if two libraries provide a function with the same name generating a conflict?

  • If you control one or both: edit one to change the name and recompile Or equivalently see Ben and unknown's answers which will work without access to the source code.
  • If you don't control either of them you can wrap one of them up. That is compile another (statically linked!) library that does nothing except re-export all the symbols of the original except the offending one, which is reached through a wrapper with an alternate name. What a hassle.
  • Added later: Since qeek says he's talking about dynamic libraries, the solutions suggested by Ferruccio and mouviciel are probably best. (I seem to live in long ago days when static linkage was the default. It colors my thinking.)

Apropos the comments: By "export" I mean to make visible to modules linking to the library---equivalent to the extern keyword at file scope. How this is controlled is OS and linker dependent. And it is something I always have to look up.

Change Subroutine Names at Build Time to Avoid Collisions in Xcode

Why isn't xcode calling the correct library function?

Let's say I have 3 C libraries as mentioned by you. Let's say it has the following code.

Library 1 - test1lib.a with code:

#include <stdio.h>

void doStuff()
{
printf("\nDoing stuff for lib1\n");
}

void uniqueEntryPoint1()
{
printf("\nUnique entry point for lib1\n");
doStuff();
}

Library 2 - test2lib.a with code:

#include <stdio.h>

void doStuff()
{
printf("\nDoing stuff for lib2\n");
}

void uniqueEntryPoint2()
{
printf("\nUnique entry point for lib2\n");
doStuff();
}

Library 3 - test3lib.a with code:

#include <stdio.h>

void doStuff()
{
printf("\nDoing stuff for lib3\n");
}

void uniqueEntryPoint3()
{
printf("\nUnique entry point for lib3\n");
doStuff();
}

Here each library has a unique function and one common function doStuff()

When we add these 3 libraries to xcode and link them. xcode links but does not load all the objects files. Let's say the objective C code is like this:

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
uniqueEntryPoint1();

}

The output is

Unique entry point for lib1

Doing stuff for lib1

In this case xcode will only load symbols which are referred (library 1 objects) in this case.

If you are read about linker flags/options such as -all_load, -force_load and -objC, you will have better understanding.

If we add -all_load linker option, it will force linker to load all the objects of libraries so we will get the following error in xcode

ld: 2 duplicate symbols for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

The reason this fails as the linker detects that doStuff() is redefined multiple times.

The only way around this problem is change the linker input i.e. symbols present in these 3 libraries. This is already mentioned by Josh in the comments. I will add my $0.02 to it.

Possible Solutions

Solution 1:

The best solution (self explanatory) is to change the source code if you have access to the same.

Solution 2:

Use objcopy to rename or prefix the function as provided in the answer of this How to deal with symbol collisions between statically linked libraries?

Now your doubt on how to find the objcopy.

Option 1:
You can use this project https://github.com/RodAtDISA/llvm-objcopy. This will be tricky to compile as it builds along with llvm. You will have to follow instructions at http://llvm.org/docs/GettingStarted.html and http://llvm.org/docs/CMake.html.

If you rewrite the https://github.com/RodAtDISA/llvm-objcopy/blob/master/llvm-objcopy.cpp, you can probably reuse the parsing and object rewriting logic without depending upon llvm.

Option 2:

Compile and reuse binutils objcopy from https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=binutils/objcopy.c;h=2636ab4bcb34cf1e1e54db9933018a805b366727;hb=HEAD

Solution 3:

You can follow the answer provided by Richard in this link Rewriting symbols in static iOS libraries. This is more of a hack but using a hex editor you can rewrite the symbols if their length is kept the same. If you have more symbols and its a big library, you can consider using https://sourceforge.net/projects/bbe-/ and nm to write a script.

All of this is a considerable effort but apparently there is no shortcut.



Related Topics



Leave a reply



Submit