Symbol Collisions.

Tavis Ormandy

$Id: a07cf90837a3c4373b82d6724b97593810766af7 $

Intro

I recently needed to build a binary that contained two versions of the same library. I wanted to manually examine any cases where the new version gave different results to verify the output is correct.

Read on for a solution.

Solution

    $ nm --format=posix --defined-only --extern-only libtest1.a \
        | awk '$2 ~ /[A-Z]/ { print $1,"ver1_"$1}' > sym1.lst
    $ nm --format=posix --defined-only --extern-only libtest2.a \
        | awk '$2 ~ /[A-Z]/ { print $1,"ver2_"$1}' > sym2.lst

The nm output has an uppercase type letter if it’s global, so the awk command checks if column 2 is uppercase, then appends a prefix to the name.

    $ objcopy --redefine-syms=sym1.lst libtest1.a libtest1.a
    $ objcopy --redefine-syms=sym2.lst libtest2.a libtest2.a
    $ objcopy --redefine-syms=sym1.lst want-ver1.o want-ver1.o
    $ objcopy --redefine-syms=sym2.lst want-ver2.o want-ver2.o

Then you can link as usual. I automated all this with a Makefile, something like:

symbols.lst: libtest1.a

libtest1.a: path/to/version1/libtest.a
    nm --format=posix --defined-only --extern-only $@ | awk '$$2 ~ /[A-Z]/ { print $$1,"ver1_"$$1}' > symbols.lst
    objcopy --redefine-syms=symbols.lst $@ $@

wantver1.o: wantver1.c | symbols.lst
    $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
    objcopy --redefine-syms=symbols.lst $@ $@