I made a piece of code which consists in a dynamic library (lib.c
), and a main executable (main.c
).
In both files I define a global variable named: int global
.
Not very smart but it's not the question.
When I compile the dynamic library the -fPIC
option seems mandatory:
gcc lib.c -fPIC -shared -o lib.so
otherwise I get:
/usr/bin/ld: /tmp/ccpUvIPj.o: relocation R_X86_64_32 against '.rodata' can not be used when making a shared object; recompile with -fPIC
When I compile the executable it is not.
gcc main.c -fPIC -ldl
gcc main.c -ldl
Both work, but have different behaviours I can not explain, could you ? :
with -fPIC, global in main.c and global in lib.c are the same variables:
global main: 23 (0x601050)
global lib: 23 (0x601050)
without -fPIC, global in lib.c is not correlated to global in main.c:
global main: 23 (0x601048)
global lib: 0 (0x7f7742e64028)
Here is the source :
lib.c
#include <stdio.h>
#include <stdlib.h>
int global;
int f_one() {
printf("global lib: %d (%p)\n", global, &global);
return EXIT_SUCCESS;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void * handle;
int global;
int main() {
int q = 7;
int (* f_one_p)(int a) = NULL;
global = 23;
handle = dlopen("./lib.so", RTLD_NOW);
if (handle == 0) {
return EXIT_FAILURE;
}
f_one_p = dlsym(handle, "f_one");
printf("global main: %d (%p)\n", global, &global);
f_one_p(q);
return EXIT_SUCCESS;
}
gcc --version: gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
uname -a: Linux xxx 2.6.38-11-generic #48-Ubuntu SMP Fri Jul 29 19:02:55 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux
edit: code tested under SUN/sparc and x86/Linux architectures with the same kind of unexpected shared global variables (with -fPIC).
When you compile with -fPIC
the object in question will determine the address of global symbols using the Global Offset Table. What happens though when part of the code is -fPIC
and part isn't is that one of your int global
s will be using this table to determine the address whilst the other part isn't.
If you had two shared object linked with -fPIC
, but your main program not then you would still have two addresses for int global
, one using the global offset table and one which was just local to the non-PIC code.
There's a really great discussion on PIC vs pic vs non PIC if you want to read further.
By default, when building an executable references to variables are done internally, with a fixed offset and no relocation.
However, you're passing -fPIC
and access to global data are converted to access via GOT and GOT relocations are added.
来源:https://stackoverflow.com/questions/7298186/global-variables-shared-libraries-and-fpic-effect