Bartleby 0.1.0
A symbol renaming toolkit
Loading...
Searching...
No Matches
Why not objcopy?

Introduction

This page is a brief overview of the objcopy(1) tool.

objcopy(1) offers several options that could be used to solve symbol collisions across libraries.

However, it has some limitations that makes it harder to use on large set of libraries.

Through this overview, we demonstrate that objcopy is not a suitable solution to the symbol name collisions problem.

The –redefine-sym option

The --redefine-sym option renames a given symbol:

–redefine-sym old=new

  • Change the name of a symbol old, to new. This can be useful when one is trying link two things together for which you have no source, and there are name collisions.

Here is a small example of --redefine-sym, ran on a simple object that defines the SSL_CTX_new symbol:

$ nm 1.o
0000000000000000 T SSL_CTX_new
$ objcopy --redefine-sym SSL_CTX_new=__private_SSL_CTX_new
$ nm 1.o
0000000000000000 T __private_SSL_CTX_new

We successfully renamed the SSL_CTX_new symbol to __private_SSL_CTX_new. However, it does not scale for large libraries, nor for large set of objects. Thus, objcopy(1) provides the --redefine-syms option, to solve that scaling issue.

The –redefine-syms option

--redefine-syms acts like --redefine-sym, but takes a file containing the symbols to rename:

–redefine-syms=filename

Apply –redefine-sym to each symbol pair "<em>old new</em>" listed in the file filename.
filename is simply a flat file, with one symbol pair per line. Line comments may be introduced by the hash character.
This option may be given more than once.

Although this option may solve the scaling issue --redefine-sym has, it is not easy to use: one has to generate the list of symbols defined by the target library, and also has to map the new name for each of these symbols.

The –prefix-symbols option

It is often sufficient to append a prefix to all the symbol names, in order to make then unique.

For instance, one can prefix all the symbol names from an external library with __private_mylib_external_.

objcopy(1) has the --prefix-symbols option for that purpose:

–prefix-symbols=string

Prefix all symbols in the output file with string.

The following is an example of that option on the same simple object used in our previous example:

$ objcopy --prefix-symbols=__private__mylib_external_ 1.o
$ 0000000000000000 T __private__mylib_external__SSL_CTX_new

But this option has a major drawback: it renames all symbols in the target object, even the undefined ones that may be defined by an external library, such as the libc.

Example

Giving the following C code:

#include <stdio.h>
// Compile with cc -fvisibility=hidden -c a.c
__attribute__((visibility("default"))) void display_filename(void) {
fputs(__FILE__, stdout);
}

We end up with the symbol list below:

$ clang -fvisibility=hidden -c a.c
$ nm a.o
0000000000000000 T display_filename
U fputs
0000000000000000 r .L.str
U stdout
  • display_filename is defined by our object (indicated by the flag T).
  • fputs is undefined (indicated by the flag U).
  • stdout is also undefined.

These undefined symbols are well-known symbols belonging to the libc.

Now, we run --prefix-symbols on a.o:

$ objcopy --prefix-symbols=__private_ a.o
$ nm a.o
0000000000000000 T __private_display_filename
U __private_fputs
0000000000000000 r __private_.L.str
U __private_stdout

As expected, display_filename has been prefixed correctly, however our undefined symbols have also been prefixed. This is not correct, because when this object is linked to produce a final binary, the link will attempt to find the symbols __private_fputs and __private_stdout, which are obviously not defined in the libc:

// main.c
extern void __private_display_filename(void);
#define display_filename __private_display_filename
int main() {
display_filename();
return 0;
}
$ clang -c main.c
$ clang -o main main.o a.o
/usr/bin/ld: a.o: in function `__private_display_filename':
__private_a.c:(.text+0x7): undefined reference to `__private_stdout'
/usr/bin/ld: __private_a.c:(.text+0x16): undefined reference to `__private_fputs'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Because it would not be a great solution to also prefix the symbols from the libc, --prefix-symbols is not a solution to our problem neither.

Conclusion

Even if objcopy(1) offers at least three mechanism for renaming symbols, we saw that none of them really fit our use case.

We can also add the techniques we described earlier imply that the developer has to somehow specify for each symbol its new name. This is a major issue when it comes with external dependencies: it means that every header file has to be patched according to the new symbol names.

Bartleby is based on the LLVM implementation of objcopy. LLVM also provides its own objcopy tool, called llvm-objcopy .

References