LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Static variable sharing in shared libraries (https://www.linuxquestions.org/questions/programming-9/static-variable-sharing-in-shared-libraries-492837/)

ristiisa 10-16-2006 09:28 AM

Static variable sharing in shared libraries
 
Hello,
I have 2 shared libraries(slave and common) and one binary executable(host). host uses slave and both host and slave use common.
Code:

[host]->[slave]
  \      /
  [common]

In common there is a static variable that can be set/get through commons setCommonValue/getCommonValue functions. I link slave statically with common and host shared with slave and common.
The problem is that when i call a method from slave that calls setCommonValue from common and now i call getCommonValue(in host) the value set in slave is returned.
1) why?
2) how could i link so that this problem does not arise?

The sample output. I expect 1000 and 1000
Code:

$ ./host
1000
Slave acts
500

Code:

$ldd host
        libslave.so => not found
        libcommon.so => not found
        libstdc++.so.5 => /usr/lib/libstdc++.so.5 (0x40027000)
        libc.so.6 => /lib/tls/libc.so.6 (0x400e1000)
        libm.so.6 => /lib/tls/libm.so.6 (0x40216000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x40238000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

Code:

$ldd libslave.so
      libc.so.6 => /lib/tls/libc.so.6 (0x40011000)
      /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)

Code:

$ nm -g libslave.so | grep ' T '
00000784 T doSlaveStuff
00000830 T _fini
000007ca T getCommonValue
0000062c T _init
000007b0 T setCommonValue

Code:

$ldd libcommon.so
      libc.so.6 => /lib/tls/libc.so.6 (0x40011000)
      /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)

The code:
make case1 builds my sample.
Code:

//common.h
#ifdef __cplusplus
extern "C" {
#endif

void setCommonValue(int value);
int getCommonValue();

#ifdef __cplusplus
} // extern "C"
#endif

Code:

//common.cpp
#include "common.h"
static int common_value;
void setCommonValue(int value){
        common_value = value;
}

int getCommonValue(){
        return common_value;
}

Code:

//slave.h
#ifdef __cplusplus
extern "C" {
#endif

const char* doSlaveStuff();

#ifdef __cplusplus
} // extern "C"
#endif

Code:

//slave.cpp
#include "slave.h"
#include "common.h"
const char * doSlaveStuff(){
        setCommonValue(500);
    return "Slave acts";
}

Code:

//host.cpp
#include <iostream>
#define SHAREDSLAVE
#include "slave.h"
#include "common.h"
using namespace std;

int main(){
        setCommonValue(1000);
        cout << getCommonValue() << endl;
    cout << doSlaveStuff() << endl;
    cout << getCommonValue() << endl;
    return 0;
}

Code:

#Makefile
all: clean slave slave.so host common

clean:
        rm -f slave.o
        rm -f libslave.a
        rm -f libslave.so
        rm -f libcommon.a
        rm -f libcommon.so
        rm -f host

slave:
        gcc -fPIC -c slave.cpp -o slave.o
        ar -cru libslave.a slave.o

slave.so:
        gcc -shared slave.o -o libslave.so -L. -lcommon

host:
        gcc -u setCommonValue main.cpp -o host -L. -lslave -lcommon -lstdc++

common:
        gcc -fPIC -c common.cpp -o common.o
        ar -cru libcommon.a common.o

common.so:
        gcc -c common.cpp -o common.o
        gcc -shared common.o -o libcommon.so

case1: clean common slave slave.so common.so host


xhi 10-16-2006 09:42 AM

i dont understand why you are expecting 1000, 1000 when clearly you are setting the value to 1000, and then 500. ??

Code:

const char * doSlaveStuff(){
        setCommonValue(500);
    return "Slave acts";
}
...
int main(){
        setCommonValue(1000);  // <-- you are setting 1000 here
        cout << getCommonValue() << endl;
    cout << doSlaveStuff() << endl;  // <-- you are setting it to 500 here (see above)
    cout << getCommonValue() << endl;
    return 0;
}

or am i missing something?

paulsm4 10-16-2006 09:46 AM

Hi -

I think maybe you have the wrong expectations.

A variable is just a variable: it doesn't matter if it's from a shared library (.so), a static library (.a) or a static object (.o) - it's exactly the same in every case.

Here are a couple of links that might explain a bit better:

http://en.wikipedia.org/wiki/Library_(computer_science)
http://www.iecc.com/linker/linker10.html

SUGGESTION:
What's the problem you're really trying to solve? When you said "problem" above, you were actually restating "what" you were doing, not the "why". If we knew the "requirement", the actual goal, then perhaps we could suggest some alternatives for you.

Tischbein 10-16-2006 11:44 AM

Yes, it's the same common variable. Make a "cookie" :) containing the data specific to each of common's "clients" and get the client to look after it! I mean a struct, of course.

---------
Common:

typedef COMMON_COOKIE {...}

---------
Client such as slave or master:

COMMON_COOKIE my_common;

set_common_value(my_common, 27);

----------

ristiisa 10-17-2006 02:12 AM

Quote:

Originally Posted by xhi
i dont understand why you are expecting 1000, 1000 when clearly you are setting the value to 1000, and then 500. ??

Code:

const char * doSlaveStuff(){
        setCommonValue(500);
    return "Slave acts";
}
...
int main(){
        setCommonValue(1000);  // <-- you are setting 1000 here
        cout << getCommonValue() << endl;
    cout << doSlaveStuff() << endl;  // <-- you are setting it to 500 here (see above)
    cout << getCommonValue() << endl;
    return 0;
}

or am i missing something?

Host uses common as a shared library, but slave uses common in a static library. I thought the memory spaces would not overlap.

ristiisa 10-17-2006 02:18 AM

Quote:

Originally Posted by paulsm4
Hi -

I think maybe you have the wrong expectations.

A variable is just a variable: it doesn't matter if it's from a shared library (.so), a static library (.a) or a static object (.o) - it's exactly the same in every case.

Here are a couple of links that might explain a bit better:

...

SUGGESTION:
What's the problem you're really trying to solve? When you said "problem" above, you were actually restating "what" you were doing, not the "why". If we knew the "requirement", the actual goal, then perhaps we could suggest some alternatives for you.

Well the problem is how to use common so that the variable would stay unchanged in host if slave changes it and vice versa? Consider the common to be a third-party library that both host and slave would like to use simultaneously.

ristiisa 10-17-2006 02:21 AM

Quote:

Originally Posted by Tischbein
Yes, it's the same common variable. Make a "cookie" :) containing the data specific to each of common's "clients" and get the client to look after it! I mean a struct, of course.

---------
Common:

typedef COMMON_COOKIE {...}

---------
Client such as slave or master:

COMMON_COOKIE my_common;

set_common_value(my_common, 27);

----------

In this case changing the common is not an option. But good suggestion.

ristiisa 10-17-2006 03:58 AM

I read about -Bsymbolic option in gcc, it seemed thats what i need, but no effect whatsoever. any ideas?

ristiisa 10-17-2006 05:32 AM

In this case are there duplicate symbols? One get/setCommonValue in common and one in slave(when linked staticly with common).

I did a experiment:
Code:

#include "common.h"
static int common_value1;
static int common_value2;
void setCommonValue(int value){
        #ifdef USEVAL1
        common_value1 = value;
        #else
        common_value2 = value;
        #endif
}

int getCommonValue(){
        #ifdef USEVAL1
        return common_value1;
        #else
        return common_value2;
        #endif
}

I compiled common with -DUSEVAL1 and then compiled slave and linked them. Then i compiled common winthout USEVAL1 into shared library. But no success...

ristiisa 10-19-2006 05:13 AM

Well i have solved the problem by implementing a version script. So...
Code:

$ cat slave.v
{ global: doSlaveStuff; local: * ; };

And i compiled the project with...
Code:

gcc -Wall -fPIC -c common.cpp -o common.o
ar -cru libcommon.a common.o
gcc -Wall -fPIC -c slave.cpp -o slave.o
gcc -Wall -shared -Wl,--version-script=slave.v slave.o -o libslave.so -L. -lcommon
gcc -Wall -shared common.o -o libcommon.so
gcc -Wall main.cpp -o host -L. -lslave -lcommon -lstdc++

Finally...
Code:

$ ./host
1000
Slave acts
1000

I thank everybody for their help.
Cheers!

xhi 10-19-2006 07:47 AM

interesting... what is the version script doing?

paulsm4 10-19-2006 10:43 AM

ristiisa -

I strongly suspect that whatever you *think* you got working is probably more by coincidence than by design. I still think you've got some fundamental misconceptions about how processes can access and share global data with each other, and about what shared libraries can (or cannot!) do for you.

Please do glance at these links (if you haven't already):

http://en.wikipedia.org/wiki/Shared_libraries
http://www.iecc.com/linker/linker10.html
http://people.redhat.com/drepper/dsohowto.pdf

IMHO .. PSM

exvor 10-19-2006 01:32 PM

I was gonna say make them static or just pass the value to the functions and not use a golbal variable. Then again this is C++ witch I stay away from :p

ristiisa 10-20-2006 09:08 AM

Quote:

Originally Posted by paulsm4
ristiisa -

I strongly suspect that whatever you *think* you got working is probably more by coincidence than by design. I still think you've got some fundamental misconceptions about how processes can access and share global data with each other, and about what shared libraries can (or cannot!) do for you.

Please do glance at these links (if you haven't already):

http://en.wikipedia.org/wiki/Shared_libraries
http://www.iecc.com/linker/linker10.html
http://people.redhat.com/drepper/dsohowto.pdf

IMHO .. PSM

The real life problem was that i had a application using Qt and a shared library using Qt. Both designed so that using them together resulted conflict in sharing Qt's global variables(like db connections and text codecs). The reason was in the design of that shared library, designed to be cross platform but forgot to take notice about shared library behavior under linux. Perhaps the solution i found was a mere coincidence or a loophole but on windows dll's act like that in the first place. You have to go extra trouble for wanting to export your symbols and to import foreign exported symbols. If i compile the same project under windows with gcc and with ms compiler then gcc exports everything and cl exports nothing.


All times are GMT -5. The time now is 04:18 AM.