In C, declaring a variable static at the global level (outside any function) indicates that it is visible only to that linker object (typically, that .C file).
If the same .C file is part of multiple different libraries that are then linked together in a single executable, do conflicts arise?
For example:
MyFile.c
typedef struct {
[my important data];
} MyGlobalType;
static MyGlobalType globalData = { [...data...] };
Then if I have:
Plugin_Alpha.so: composed of MyFile.C + AlphaSource.C
Plugin_Beta.so: composed of MyFile.C + BetaSource.C
MainProgram.exe: composed of MainCode.C (which loads the two plugins)
Will Plugin_Alpha and Plugin_Beta have separate, isolated copies of globalData?
Or will they end up referring to the same structure?
Well, here's one way to find out:
File liba.c:
static int globalData;
int *GetGlobalData() { return &globalData; }
Compile into two separate shared libraries:
$ gcc liba.c -o liba.so -fPIC -shared
$ gcc liba.c -o libb.so -fPIC -shared
Main program:
#include <dlfcn.h>
#include <stdio.h>
int main(void)
{
// Error checking omitted for expository purposes
void *liba = dlopen("liba.so", RTLD_LAZY);
void *libb = dlopen("libb.so", RTLD_LAZY);
typedef int* (*FuncV_IP)(void);
FuncV_IP funca = (FuncV_IP)dlsym(liba, "GetGlobalData");
FuncV_IP funcb = (FuncV_IP)dlsym(libb, "GetGlobalData");
printf("Module A: GetGlobalData() ==> %p\n", funca());
printf("Module B: GetGlobalData() ==> %p\n", funcb());
dlclose(liba);
dlclose(libb);
return 0;
}
Compile and run it:
$ gcc main.c -ldl
$ LD_LIBRARY_PATH=. ./a.out
Output:
Module A: GetGlobalData() ==> 0x7fa97536d020
Module B: GetGlobalData() ==> 0x7fa97516b020
So therefore, each shared library gets its own copy of the global variables.
Related
I have the following two files:
// t.c
#include<stdio.h>
extern int x;
int main(void)
{
printf("%d\n", x);
}
// tt.c
int x=4;
And then I compile it into two object files with:
$ gcc -c tt.c t.c
So now I have two object files, tt.o and t.o. When I do the following to build an executable:
$ gcc tt.o t.o -o out
How does the linker resolve the definition of x? Does it basically do a "two-pass" where it saves all global variables with external linkage first, and then does a lookup in each file that needs an external definition, or what's the process that happens to resolve those lookups?
On Windows it is possible to dynamically link to an executable with exported symbols. For example following code:
// main.c
void __declspec(dllexport) interface_function() {}
int main() {}
// ext.c
void interface_function();
void extension_function() {
interface_function();
}
With
cl.exe main.c
cl.exe ext.c /LD /link main.lib
would produce an executable main.exe, a static library main.lib for implicit linking, and a dynamic library ext.dll.
Similar behavior can be achieved in OSX with shared libraries:
// main.c
void interface_function() {}
int main() {}
// ext.c
void interface_function();
void extension_function() {
interface_function();
}
With
gcc main.c -o main
gcc ext.c -bundle -bundle_loader main -o ext.bundle
it is virtually equivalent to the Windows setup.
But for dynamiclib:
> gcc ext.c -dynamiclib -o ext.dylib
and shared:
> gcc ext.c -shared -o ext.so
I cannot get them to work because of undefined symbols on one hand and unable to load an executable with -l flag on the other.
I can let them resolve undefined symbols in runtime with -undefined dynamic_lookup. But this is not a sustainable way because all the link errors are now happening in run-time instead.
Is there a way to provide the list of symbols to dynamically load from an executable when linking as -shared and -dynamiclib?
Yes this is possible, but then you'll want to create a bundle rather than a shared library (see this answer for more detail).
If you have a main application like so:
#include <stdio.h>
#include <dlfcn.h>
int func(void)
{
return 42;
}
int main(void)
{
void *dl = dlopen("plugin.so", RTLD_LOCAL);
if(!dl) return -1;
int (*derp)(void) = dlsym(dl, "derp");
if(!derp) return -1;
printf("derp(): %i\n", derp());
return 0;
}
clang -o main main.c -Wall -Wl,-export_dynamic
Then you can compile bundles against it like so:
int func(void);
int derp(void)
{
return -func();
}
clang -o plugin.so plugin.c -Wall -bundle -bundle_loader ./main
We have a program that links in a number of static libraries, which may or may not define a number of symbols depending on compilation options. On OS X, we use dlsym(3) with a NULL handle to obtain the symbol addresses. However, on Linux, dlsym(3) always returns NULL.
Consider a trivial program (sources below) that links in a static library containing a function and a variable and tries to print their addresses. We can check that the program contains the symbols:
$ nm -C test | grep "test\(func\|var\)"
0000000000400715 T testFunc
0000000000601050 B testVar
However, when the program is run, neither can be located:
$ ./test
testVar: (nil)
testFunc: (nil)
Is what we are trying to do possible on Linux, using glibc's implementation of dlsym(3)?
Makefile
(Sorry about the spaces)
LDFLAGS=-L.
LDLIBS=-Wl,--whole-archive -ltest -Wl,--no-whole-archive -ldl
libtest.o: libtest.c libtest.h
libtest.a: libtest.o
test: test.o libtest.a
clean:
-rm -f test test.o libtest.o libtest.a
libtest.h
#pragma once
extern void *testVar;
extern int testFunc(int);
libtest.c
#include "libtest.h"
void *testVar;
int testFunc(int x) { return x + 42; }
test.c
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char *argv[]) {
void *handle = dlopen(NULL, 0);
void *symbol = dlsym(handle, "testVar");
printf("testVar: %p\n", symbol);
symbol = dlsym(handle, "testFunc");
printf("testFunc: %p\n", symbol);
return 0;
}
You should link your program with -rdynamic (or --export-dynamic for ld(1)) so
LDFLAGS += -rdynamic -L.
Then all the symbols are in the dynamic symbol table, the one used by dlsym
BTW, the visibility attribute could be of interest.
Using GCC, how can I remove a symbol from a shared object after I've created the shared object? If I have three files in C manipulating symbol foo() like:
// a.c
int foo() { return 0xdead; }
int baz() { return 1; }
and
// b.c
int foo() { return 0xbeef; }
int bar() { return 0; }
and
// c.c
#include "stdio.h"
extern int foo();
extern int bar();
extern int baz();
int main() { printf("0x%x, 0x%x, 0x%x\n",foo(),bar(),baz()); return 0; }
Then I compile and run like:
% gcc a.c --shared -fPIC -o a.so
% gcc b.c --shared -fPIC -o b.so
% setenv LD_LIBRARY_PATH . # export LD_LIBRARY_PATH=. for bash systems
% gcc c.c a.so b.so -o c
% ./c
0xdead, 0x0, 0x1
How can I make it so that a.so no longer has symbol foo() after I've created a.so? I want the foo() defined in b.so to be used instead of a.so by deleting the foo() symbol from a.so. After foo() is deleted from a.so, rerunning c should generate a printout of:
0xbeef, 0x0, 0x1
In this toy example, I know I can simply re-order the libary names when I compile c.c with a.so and b.so, but how can I actually delete the symbol from a.so? I imagine that after deleting foo() from a.so, this grep of the nm output would yield nothing:
nm -a a.so | grep foo
Whereas right now it returns:
000000000000063c T foo
You should be able to use the -N (--strip-symbol) option of objcopy to achieve what you want:
$ objcopy -N foo a.so
Symbol visibility seems like a superior solution to select which functions are up for runtime linking and which are local to the library but still "extern" declared to allow usage from other .c files that comprise the library - http://gcc.gnu.org/wiki/Visibility .
I want to access the global variable of executable in shared library? I have tried to compile using option -export-dynamic but no luck.
I have tried with extern key word. this also not working.
Any help or suggestion would be appreciable.
Environment c - Linux
executable:-
tst.c
int tstVar = 5;
void main(){
funInso();
printf("tstVar %d", tstVar);
}
lib:-
tstLib.c
extern int tstVar;
void funInso(){
tstVar = 50;
}
Since my code is very big, I just gave the sample which I have used in my program.
It should work. BTW, your tst.cis lacking a #include <stdio.h>. And its main should return an ìnt and end with e.g. return 0;.
With
/* file tst.c */
#include <stdio.h>
int tstVar = 5;
extern void funInso(void);
int main(){
funInso();
printf("tstVar %d\n", tstVar);
return 0;
}
and
/* file tstlib.c */
extern int tstVar;
void funInso(){
tstVar = 50;
}
I compiled with gcc -Wall -c tst.c the first file, I compiled with gcc -Wall -c tstlib.c the second file. I made it a library with
ar r libtst.a tstlib.o
ranlib libtst.a
Then I linked the first file to the library with gcc -Wall tst.o -L. -ltst -o tst
The common practice is to have with your library a header file tstlib.h which would contain e.g.
#ifndef TSTLIB_H_
#define TSTLIB_H_
/* a useful explanation about tstVar. */
extern int tstVar;
/* the role of funInso. */
extern void funInso(void);
#endif /*TSTLIB_H */
and have both tst.c and tstlib.c contain an #include "tstlib.h"
If the library is shared, you should
compile the library file in position independent code mode
gcc -Wall -fpic -c tstlib.c -o tstlib.pic.o
link the library with -shared
gcc -shared tstlib.pic.o -o libtst.so
Note that you can link a shared object with other libraries. You could have appended -lgdbm to that command, if your tstlib.c is e.g. calling gdbm_open hence including <gdbm.h>. This is one of the many features shared libraries give you that static libraries don't.
link the executable with -rdynamic
gcc -rdynamic tst.o -L. -ltst -o tst
Please take time to read the Program Library Howto
your tstVar variable could be defined in the lib. and you can share this variable via functions:
setFunction: to edit this variable
void setFunction (int v)
{
tstVar = v;
}
getFunction: to return the variable
int getFunction ()
{
return tstVar
}