Though some posts exist about the -fPIC
effect (see this SO post for example) most of them are unclear. I wrote an extremely simple example and I still can't figure out what happens w/o -fPIC
regarding the location of global variables. Here is my C file:
$ cat main.c
#include <stdio.h>
int var1 = 94;
int var2 = 76;
int main(int argc, char **argv)
{
int var1Loc = (int) &var1;
int var2Loc = (int) &var2;
printf("var1 address is: %d\n",var1Loc);
printf("var2 address is: %d\n",var2Loc);
printf("diff is: %d\n",var2Loc-var1Loc);
return var1+var2;
}
Then I compile it with -fPIC
and run it twice:
$ gcc -Wno-pointer-to-int-cast -O0 -g -o main main.c
$ ./main
var1 address is: -2019672048
var2 address is: -2019672044
diff is: 4
$ ./main
var1 address is: 1441697808
var2 address is: 1441697812
diff is: 4
When I do the exact same thing without -fPIC
I get similar results. I thought that without the -fPIC
the addresses
should be identical across runs no?
In an acronym (or initialism): ASLR — Address Space Layout Randomization.
Wikipedia on ASLR says:
ASLR randomly arranges the address space positions of key data areas of a process, including the base of the executable and the positions of the stack, heap and libraries.
This describes what you're seeing. You subsequently found that using:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
to turn ASLR off meant that the addresses are the same across runs, either with or without -fPIC
, thus confirming that ASLR was the cause of the address changes.
Note that your address printing should probably use the %p
format and void *
arguments (though you have a potentially truncating data conversion when you apply the (int)
cast to the addresses — but the format is correct to use %d
). The type modifier t
is for ptrdiff_t
, the difference between two pointers.
#include <stdio.h>
int var1 = 94;
int var2 = 76;
int main(void)
{
void *var1Loc = &var1;
void *var2Loc = &var2;
printf("var1 address is: %p\n", var1Loc);
printf("var2 address is: %p\n", var2Loc);
printf("diff is: %td\n", &var2 - &var1);
return 0;
}