I have an issue with global variables in shared library on Solaris.
Consider following sample:
class Foo
{
public:
Foo() { Init(); }
private:
void Init() { // do something }
};
I have some code in shared library:
Foo g_Foo;
I've noticed that Foo constructor is never called on Solaris while the same code works Linux.
I'm using gcc 3.4.3 and Sun linker.
Are you creating the shared object with the -G flag? e.g.
CC -G -o mylib.so myfile.cpp
If you don't specify -G, then the compiler may not initialise global variables correctly. See compiler documentation here.
Note, the docs also say you can't use ld, but need to use CC to do the linking.
Related
I'm not a frequent user of Linux and I think I did something wrong.
This is the code for a test dynamic library ".so" I'm generating.
class InternalClass
{
public:
int Function(){ return 10; }
};
extern "C"
{
int WrapperFunctionSimple() { return 10; }
void WrapperCreateInstance() {InternalClass* item = new InternalClass(); delete item; }
}
The compilation fails with the following error:
g++ -Wall -fexceptions -O2 -c /home/lidia/compartida/TestLibrary/TestLibrary/main.cpp -o obj/Release/main.o
g++ -shared obj/Release/main.o -o bin/Release/libTestLibrary.so -s
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: obj/Release/main.o: warning: relocation against `_Znwm##GLIBCXX_3.4' in read-only section `.text'
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: obj/Release/main.o: relocation R_X86_64_PC32 against symbol `_Znwm##GLIBCXX_3.4' can not be used when making a shared object; recompile with -fPIC
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
I tried with -fPIC as suggested and it compiles. But when using this library, It cannot be loaded when I add that last function:
void WrapperCreateInstance() {InternalClass* item = new InternalClass(); delete item; }
The problem is using the InternalClass, without this function everything works.
I'm using VirtualBox. I installed OpenSUSE 64bit, the app that uses the library is also 64bit. In another linux distribution (Mint), with exactly the same project and settings (without fPIC), it can be compiled. When I use that library (.so) it works in SUSE.
I'm also using :
gcc (SUSE Linux) 7.5.0
g++ (SUSE Linux) 7.5.0
My IDE is Code::Blocks 20 (last version). Settings are empty except for the -m64 flag.
What am I doing wrong? This seems like something advanced Linux users could help me understand.
EDIT:
To add more information, this can compile in Ubuntu with the same settings. Not in SUSE
To me it happened, if one library (A) depends on another one (B) and library A was linked before library B. The solution is to link library B first and then A.
It happened to me when I used GCC to compile a CPP file. So for C++ files use g++ only, and obviously not GCC, which is meant for c files.
I am using cmake and GCC in ubuntu and I got the same error.
In my case, I added the XX.h file to include directories, and used in my main.cpp a "typedef struct x" which is defined in XX.h header file. However I forgot to add XX.c to the executable sources.
This error is cleared when I added XX.c to the target executable sources in add_executable() of Cmake.
I hope I can clearly state my case.
In my case this happened when I had an abstract class A and two derived classes B and C like below.
class BaseAbstractClass
{
public:
virtual void doNothing(void) = 0;
};
class A : public BaseAbstractClass
{
public:
void doNothing(void){
return;
}
};
class B : public BaseAbstractClass
{
public:
void doNothing(void); // Only declaration, definition is nowhere
};
But one of derived classes (class B here) has only declaration of doNothing(), but lacks definition anywhere in project files.
I had a similar issue and the order of linking answer was useful for me. It ended up being I was including the cpp file rather than the header (include was called at wrong time.)
I am trying to re-compile an existing C++ application.
Unfortunately, I must rely on a proprietary library I only have a pre-compiled static archive of.
I use g++ version 7.3.0 and ld version 2.30.
Whatever GCC version it was compiled with, it is ancient.
The header file defines the method:
class foo {
int bar(int & i);
}
As nm lib.a shows, the library archive contains the corresponding exported function:
T bar__4fooRi
nm app.o shows my recent compiler employing a different kind of name mangling:
U _ZN4foo9barERi
Hence the linker cannot resolve the symbols provided by the library.
Is there any option to chose the name mangling algorithm?
Can I introduce a map or define the mangled names explicitly?
#Botje's suggestion lead me to writing a linker script like this (the spaces in the PROVIDE stanza are significant):
EXTERN(bar__4fooRi);
PROVIDE(_ZN4foo9barERi = bar__4fooRi);
As far as I understood, this will regard bar__4fooRi as an externally defined symbol (which it is). If _ZN4foo9barERi is searched for, but not defined, bar__4fooRi will take its place.
I am calling the linker from the GNU toolchain like this (mind the order – the script needs to be after the dependant object but before the defining library):
g++ -o application application.o script.ld -lfoo
It looks like this could work.
At least in theory.
The linker now regards other parts of the library, which in turn depends on other unresolvable symbols including (but not limited to) __throw, __cp_pop_exception, and __builtin_delete. I have no idea where these functions are defined nowadays. Joxean Koret shows some locations in this blog post based on guesswork (__builtin_new probably is malloc) – but I am not that confident.
These findings lead me to the conclusion that the library relies on a different style of exception handling and probably memory management, too.
EDIT: The result may be purely academical due to ABI changes as pointed out by #eukaryota, a linker script can indeed be used to "alias" symbols. Here is a complete minimal example:
foo.h:
class Foo {
public:
int bar(int);
};
foo.cpp:
#include "foo.h"
int Foo::bar(int i) {
return i+21;
}
main.cpp:
class Foo {
public:
int baa(int); // use in-place "header" to simulate different name mangling algorithm
};
int main(int, char**) {
Foo f;
return f.baa(21);
}
script.ld:
EXTERN(_ZN3Foo3barEi);
PROVIDE(_ZN3Foo3baaEi = _ZN3Foo3barEi); /* declare "alias" */
Build process:
g++ -o libfoo.o -c foo.c
ar rvs libfoo.a libfoo.o # simulate building a library
g++ -o app main.o -L. script.ld -lfoo
app is compiled, can be executed and returns expected result.
Edit: the comments below the accepted answer show that it might be an issue with the Android dynamic loader.
I have a header for a template class with a static member. At runtime the address of the static member is used in the library and in the client code. The template is implicitly instantiated both in the library and in the client code. It works fine on Linux and OSX, the symbol is duplicated but marked as "uniqued" as shown by nm (see below).
However when I compile for ARM (Android), the symbol is marked weak in both the DSO and the executable. The loader does not unify and the symbol is effectively duplicated at runtime!
I read these:
two instances of a static member, how could that be?
Static template data members storage
and especially this answer:
https://stackoverflow.com/a/2505528/2077394
and:
http://gcc.gnu.org/wiki/Visibility
but I am still a little bit puzzled. I understand that the attributes for visibility helps to optimize, but I thought it should work by default. I know the C++ standard does not care about shared library, but does it means that using shared libraries breaks the standard? (or at least this implementation is not C++ standard conform?)
Bonus: how can I fix it? (and not using template is not an acceptable answer:))
Header:
template<class T>
struct TemplatedClassWithStatic {
static int value;
};
template<class T>
int TemplatedClassWithStatic<T>::value = 0;
shared.cpp:
#include "TemplateWithStatic.hpp"
int *addressFromShared() {
return &TemplatedClassWithStatic<int>::value;
}
main.cpp:
#include "TemplateWithStatic.hpp"
#include <cstdio>
int *addressFromShared();
int main() {
printf("%p %p\n", addressFromShared(), &TemplatedClassWithStatic<int>::value);
}
And building, looking at the symbols definitions:
producing .so:
g++-4.8 -shared src/shared.cpp -o libshared.so -I include/ -fPIC
compiling and linking main:
g++-4.8 src/main.cpp -I include/ -lshared -L.
symbols are marked as "unique":
nm -C -A *.so a.out | grep 'TemplatedClassWithStatic<int>::value'
libshared.so:0000000000200a70 u TemplatedClassWithStatic<int>::value
a.out:00000000006012b0 u TemplatedClassWithStatic<int>::value
producing .so
~/project/android-ndk-r9/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++ -o libshared.so src/shared.cpp -I include/ --sysroot=/Users/amini/project/android-ndk-r9/platforms/android-14/arch-arm/ -shared
compiling and linking main
~/project/android-ndk-r9/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++ src/main.cpp libshared.so -I include/ --sysroot=${HOME}/project/android-ndk-r9/platforms/android-14/arch-arm/ -I ~/project/android-ndk-r9/sources/cxx-stl/gnu-libstdc++/4.8/include -I ~/project/android-ndk-r9/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include -I ~/project/android-ndk-r9/sources/cxx-stl/gnu-libstdc++/4.8/include/backward -I ~/project/android-ndk-r9/platforms/android-14/arch-arm/usr/include ~/project/android-ndk-r9/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/libgnustl_static.a -lgcc
symbols are weak!
nm -C -A *.so a.out | grep 'TemplatedClassWithStatic<int>::value'
libshared.so:00002004 V TemplatedClassWithStatic<int>::value
a.out:00068000 V TemplatedClassWithStatic<int>::value
Edit, note for the context: I was playing with OOLua, a library helping binding C++ to Lua and my unittests were failing when I started to target Android. I don't "own" the code and I would rather modifying it deeply.
Edit, to run it on Android:
adb push libshared.so data/local/tmp/
adb push a.out data/local/tmp/
adb shell "cd data/local/tmp/ ; LD_LIBRARY_PATH=./ ./a.out"
0xb6fd7004 0xb004
Android does not support unique symbols. It is a GNU extension of ELF format that only works with GLIBC 2.11 and above. Android does not use GLIBC at all, it employs a different C runtime called Bionic.
(update) If weak symbols don't work for you (end update) I'm afraid you would have to modify the code such that it does not rely on static data.
There may be some compiler/linker settings that you can tweak to enable this (have you looked at the -fvisibility flag?).
Possibly a GCC attribute modifier may be worth trying (explicitly set __attribute__ ((visibility ("default"))) on the variable).
Failing that, the only workarounds I could suggest are: (all are somewhat ugly):
Explicitly instantiate all forms of the template that are created in the shared library and provide the initializers in its implementation (not in the header). This may or may not work.
Like (1) but use a shim function as a myers singleton for the shared variable (example below).
Allocate a variable in a map for the class based upon rtti (which might also fail across a shared library boundary).
e.g.
template<class T>
struct TemplatedClassWithStatic {
static int& getValue() { return TemplatedClassWithStatic_getValue((T const*)0); }
};
// types used by the shared library.. can be forward declarations here but you run the risk of violating ODR.
int& TemplatedClassWithStatic_getValue(TypeA*);
int& TemplatedClassWithStatic_getValue(TypeB*);
int& TemplatedClassWithStatic_getValue(TypeC*);
shared.cpp
int& TemplatedClassWithStatic_getValue(TypeA*) {
static int v = 0;
return v;
}
int& TemplatedClassWithStatic_getValue(TypeB*) {
static int v = 0;
return v;
}
int& TemplatedClassWithStatic_getValue(TypeC*) {
static int v = 0;
return v;
}
The executable would also have to provide implementations for any types that it uses to instantiate the template.
I have a shared library (libtest.cpp) and a simple program (test.cpp). I want them to share a thread local variable gVar. The shared library is linked through LD_PRELOAD.
Here is my code for the shared library libtest.cpp:
#include<stdio.h>
__thread int gVar;
void print_gVar(){
printf("%d\n", gVar);
}
Below is the code for test.cpp.
#include<stdio.h>
__thread int gVar;
void __attribute__((weak)) print_gVar();
int main(){
gVar = 10;
print_gVar();
return 0;
}
And I use the following script to compile and run them.
g++ -g -shared -fPIC -olibtest.so libtest.cpp
g++ -g -fPIC -o test test.cpp
LD_PRELOAD=./libtest.so ./test
The expected result is 10 because the assignment in test.cpp will affect the gVar in libtest.cpp. However, I only got 0. It seems that the the gVar in libtest.cpp and the gVar in test.cpp are not linked.
I did some additional tests:
If I add __attribute__((weak)) to the declaration of gVar in any of the files, the output is still 0.
If I remove __thread from both files, then the result is 10 (successful).
If I add extern and __attribute__((weak)) to the declaration of gVar in libtest.cpp, there will be segmentation fault.
I guess there must be something wrong with LD_PRELOAD and __thread. But I cannot figure out.
Could anyone tell me how I can make it work? Thank you very much!
This is not possible, since thread-local-storage requires per-thread initialisation.
LD_PRELOAD will load the library even before the standard library is loaded, which messes up TLS initialisation.
Update:
Please read sections 2 and 3 of ELF Handling For Thread-Local Storage
I know there are many questions related to shared libraries on Linux but maybe because I'm tired of having a hard day trying to create a simple dynamic library on Linux (on Windows it would have taken less than 10 minutes) I can't find what happens in this case.
So, I am trying to create a library to be linked at build-time and used at run-time (not a static library, not a library to be embedded into the executable, in other words). For now it contains a simple function. These are my files:
1.
// gugulibrary.cpp
// This is where my function is doing its job
#include "gugulibrary.h"
namespace GuGu {
void SayHello() {
puts("Hello!");
}
}
2.
// gugulibrary.h
// This is where I declare my shared functions
#include <stdio.h>
namespace Gugu {
void SayHello();
}
3.
// guguapp.cpp
// This is the executable using the library
#include "gugulibrary.h"
int main() {
GuGu::SayHello();
return 0;
}
This is how I try to build my project (and I think this is what is wrong):
gcc -Wall -s -O2 -fPIC -c gugulibrary.cpp -o gugulibrary.o
ld -shared -o bin/libGugu.so gugulibrary.o
gcc -Wall -s -O2 guguapp.cpp -o bin/GuGu -ldl
export LD_LIBRARY_PATH=bin
This is saved as a .sh file which I click and execute in a terminal. The error I get when trying to link the library is this:
/tmp/ccG05CQD.o: In function `main':
guguapp.cpp:(.text.startup+0x7): undefined reference to `SayHello'
collect2: ld returned 1 exit status
And this is where I am lost. I want the library to sit in the same folder as the executable for now and maybe I need some symbols/definitions file or something, which I don't know how to create.
Thanks for your help!
In your C++ file, GuGu::SayHello is declared as a C++ symbol. In your header, you are wrapping it in an extern "C" block. This is actually undefined, as you aren't allowed to use C++ syntax (namespace) in that context. But my guess is that what the compiler is doing is ignoring the namespace and generating a C symbol name of "SayHello". Obviously such a function was never defined by your library. Take out the extern "C" bits, because your API as defined cannot be used from C anyway.
You are inconsistent with your GuGu, there are also Gugu's running around, this needs to be made consistent, then it works (At least on my computer are some Gugu's now)