I have some static library that I can't change or rebuild. The library uses global variables. Something like this:
//lib A
#include <iostream>
static int i = 0;
void printA(){
std::cout << i++ << std::endl;
}
I want to create two shared libraries that have their own "copy" of static library and its global state:
//lib B
#include "liba.h"
void printB(){
printA();
}
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
//lib C
#include "liba.h"
void printC(){
printA();
}
... and use them simultaneously:
#include "libb.h"
#include "libc.h"
int main(){
printB();
printB();
printC();
printC();
}
I expect following output:
0
1
0
1
.. but actually get:
0
1
2
3
Seems like libB
and libC
share common counter variable. If had access to libA
source code, I would rebuild it with -fvisibility=hidden
. But unfortunately I have only binary.
Is there any way to achieve expected behavior without libA
rebuilding?
Static libraries are just collections of object files that are linked into the program during the linking phase of compilation and are not relevant during runtime.
A library does not use another library as such. You reference the header library of shared library a from library b. They can both be shared. Then, when you link your executable you include both so files in the link stage.
Static libraries take longer to execute, because loading into the memory happens every time while executing. While Shared libraries are faster because shared library code is already in the memory.
On Property Pages, go to C/C++->General->Additional Include Directories and provide the path, where the header file of the library that you want to use is located. Then go to Linker->General->Additional Library Directories and specify the path, where your . lib file is located.
If LibA uses a static counter which libB and libC increment by calling printA
, then there's no way to do what you want without object file manipulation or non-portable hacks.
The linker resolves all references to global variables (even static
s) to the same symbol at link time.
If you're willing to manipulate object files, then the following should work for you:
$ objcopy --prefix-symbols=copy_ liba.a liba-copy.a
#define printA copy_ printA
#include "liba.h"
/* ... */
If you can get the symbols from the static library using nm
(the name you'll be looking for will be in the form of <counter name>.<process ID>
) and you do something like the following, then you can read and write the static counter variable at runtime:
int counter asm("<counter name>.<process ID>");
counter = 0;
Note that this process will have to be repeated after every update of the library.
You can copy the static library and rename all symbols that use the global state. Because the symbols are compiled with c++, you are out of luck, the symbols are mangled.
You can write a C interface for all the accesses and recompile the static library hiding it's symbols and then use some objcopy --prefix-symbols
org++ -Wl,--wrap=printA
to prefix/rename the C symbols.
Or you need to know beforehand the already mangled C++ names, and then call objcopy --redefine-sym _Z6printAv=_Z10printAcopyv
etc. for each symbol the library exports.
Below is the test setup that calls the objcopy
on the mangled names. I found out the symbol names by inspecting the object files, nm a.o
and nm c.o
. Here it is:
cat <<EOF >Makefile
all: liba.a b.o main.o c.o
# we have access only to liba.a only
objcopy --redefine-sym _Z6printAv=_Z10printAcopyv liba.a libacopy.a
g++ main.o b.o c.o liba.a libacopy.a -o a.out
./a.out
liba.a: a.o
ar rcs liba.a a.o
clean:
rm -fr *.o *.a *.out tmp
EOF
cat <<EOF >a.cpp
#include <iostream>
static int i = 0;
void printA(){
std::cout << i++ << std::endl;
}
EOF
cat <<EOF >b.cpp
void printA();
void printB(){
printA();
}
EOF
cat <<EOF >c.cpp
void printAcopy();
void printC(){
printAcopy();
}
EOF
cat <<EOF >main.cpp
void printB();
void printC();
int main(){
printB();
printB();
printC();
printC();
}
EOF
You can compile with make
and run:
g++ -c -o a.o a.cpp
ar rcs liba.a a.o
g++ -c -o b.o b.cpp
g++ -c -o main.o main.cpp
g++ -c -o c.o c.cpp
# we have access only to liba.a only
objcopy --redefine-sym _Z6printAv=_Z10printAcopyv liba.a libacopy.a
g++ main.o b.o c.o liba.a libacopy.a -o a.out
./a.out
0
1
0
1
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