Lab environments:
- Ubuntu 18.04, gcc 7.5.0, binutils 2.30 (2019-05-08)
- openSUSE Leap 15.5, gcc 7.5.0, binutils 2.39 (2022-10-25)
I realize this problem when building a small .so file from foo1.c .
#include <stdio.h>
extern void FooX(int);
void Foo1(int i)
{
printf("foo1(%d)\n", i);
i++;
FooX(i);
}
On openSUSE, compile it using commands:
gcc -g -c foo1.c
gcc -shared foo1.o -o libfoo1.so
The second command fails with error message:
ld: foo1.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
As suggested by above ld error message. I go back and do gcc -g -c -fPIC foo1.c, then ld succeeds.
But on Ubuntu 18.04, I do not have to explicitly assign -fPIC to gcc.
So, on openSUSE, the foo1.o must have different machine code when it lacks vs has -fPIC.
I make some effort to compare them on openSUSE.
gcc -g -c foo1.c
mv foo1.o foo1-noPIC.o
gcc -g -c -fPIC foo1.c
mv foo1.o foo1-PIC.o
objdump -dSlr -M intel foo1-noPIC.o > foo1-noPIC.txt
objdump -dSlr -M intel foo1-PIC.o > foo1-PIC.txt
Below is the difference between foo1-noPIC.txt and foo1-PIC.txt :
I also do this on Ubuntu, and foo1-noPIC.txt and foo1-PIC.txt have same content, and they equal openSUSE's foo1-PIC.txt.
Now, I confirm that Ubuntu's gcc implies -fPIC for us.
Then, my question is, is such difference hard codeded into a Linux-distro's gcc binary, or, is it affected by some configuration file on a Linux distro? If latter, which configuration file?



As you've noticed, some Linux distros build their GCC compilers with
-fPICas a default option, which you must override with-no-fPICif you don't want it; other distros build with-no-fPICthe default, which you must override with-fPIC1.Yes, it is hardcoded and No, it is not affected by any configuration file on a linux distro. However, you can always vary the default and non-default options by feeding a suitable configuration file of your own into your
gcccommands. I'll demonstrate this by switching my own stock Ubuntugccfrom default PIC to default no-PIC.Spec strings and spec files
The GCC manual: 3.20 Specifying Subprocesses and the Switches to Pass to Them, para. 1 explains:
(my emphasis)
Parsing the built-in specs
gccuses its built-in specs by default:I can extract the built-in specs to a file like this:
If you do that, you will see that
gccspecs.txtis a file of daunting goobledegook, but the documentation already referred to teaches you how to read it (though not easily).I see that the only spec-string in which
fPICis mentioned is the one for spec-namecc1. This spec-name represents a subset of the arguments that will be passed the (real) C compiler - also calledcc1- thatgcccalls to do C-language compilation.(line-continuations
\- and any sort of comments - are not valid spec-string syntax. I pretend otherwise to avoid triggering horizontal scroll.)Eek. Let's tease this out in pseudo-code, where:
gccoptionscc1.%(specname)will mean the expansion of spec-namespecname.It says:
Which is logically equivalent to the more concise:
And if we disregard everything not relevant to the
-f[no-](pic|PIC)options2, that can simplify further to:This reveals that my
gcc, by default, will react to the absence of all-f[no-](pic|PIC)options only in case it is targeting android and it has not been told to rule out an android compiler. In that case, it will react to the absence of all-f[no-](pic|PIC)input options by outputting-fPICto the compiler. If on the other hand:-mandroid), or-tno-android-cc), or-f[no-](pic|PIC)has been input,then
gccoutputs just the same-f[no-](pic|PIC)options as were input, including none.Let's confirm that:
Without input
-mandroid, without input-f[no-](pic|PIC), I expect no-f[no-](pic|PIC)output at all:Without input
-mandroid, with input-fPIC, I expect-fPICoutput:With input
-mandroid, without input-f[no-](pic|PIC), I expect-fPICoutput:With input
-mandroid, with inputfno-PIC, I expectfno-PICoutput:That all checks out.
Overriding the built-in specs with a specs file
In the absence of any of the relevant options, I can see that my
gccdefaults to PIC code if I dump its predefined macros:So I'm assured that I can successfully build a shared library from
foo.cwith without-fPIC:and indeed I did:
And for that to fail I have to perversely try:
Suppose however I would like to flip my
gccso that:-mandroidinput , without-f[no-](pic|PIC)input, I get-no-fPICoutput, instead of-fPIC-mandroidinput, without-f[no-](pic|PIC)input, I get-no-fPICoutput, instead of nothing.i.e. With or without
-mandroid, without-f[no-](pic|PIC)input, I will get-no-fPICoutput. The compiler will default to absolute code, not position independent.Reworking the
*cc1pseudo-code to that end makes it:That is just a matter of:
output -fPICwithoutput -no-fPIC,pic/PICstuff out of the scope of the{...}that enclosed it.Applying that change to the
*cc1spec string looks like so:The whole new string goes in a spec file:
Which I can use as follows.
With
-mandroid, without-f[no-](pic|PIC)input, I now expect-no-fPICoutput:Without
-mandroid, without-f[no-](pic|PIC)input, I now expect-no-fPICoutput:Feeding
specfile.txttogcchas the expected effect of undefining the built-in macros__pic__and__PIC__So with my spec file I've flipped
gccfrom default-fPICto default-no-fPIC. Which means of course linkage failure when object files compiled without-fPICare input to a-sharedlinkage:Can you make
gccsearch for a spec file?Yes and No...
No,
gccwon't search for spec file unless you specify a spec file with the-specsoption. That's the sense in there's no "configuration file" that will do the job if you just install it.Yes, in the sense that if you do specify
-spec=specfile, thengccwill search for a file with precisely the terminal name element specfile (even if it has path components) in the same places that it would search for the toolchain files it requires, such as its programs and libraries, and failing all those it will search the current directory. So if you really wanted to, you could create a subdirectoryspecs, under, say/usr/lib/gcc/x86_64-linux-gnu/<version>, put a repertoire of spec files in there spec0,...,specN, and havegccselect one of them by passing-specs=specs/specJ. Note that if you specifyspecs=specfile andgcccan't find it, it gives a fatal error; it doesn't fall back on the built-in specs.Spec files for portability magic?
Wouldn't it be cool to use a spec file to iron out the default behavioural differences between the
gccthat your source package build finds on target system A and the one it finds on target system B? It could obviate the need for some of the thorny conditional logic in your package build files.I think not. To craft a dependable spec file you would need to know exactly the differences in default behaviour that you had to iron out in all possible cases - the same knowledge you need to craft dependable build files that don't involve spec files. Hard as it is to craft dependable build files, it's even harder to craft a dependable spec file. And more important, the competence to debug a buggy build file is widespread amongst source package consumers and vastly more common than spec file expertise.
Indeed, dependable build logic means not depending on
gcc's default behaviour. There's always an option that explicitly mandates or prohibits a behaviour trait F if that is the right thing in any supported build case. You need to know whether to mandate or prohibit F, for each supported build case, and logically arrange that the build specifies the correct option. Best to keep all this in plain sight to the utmost practical extent, in the build files and in their console output. Using spec files would be an obfuscatory approach.This schism started in 2013, when Debian moved to default PIC.
There is a fine technical distinction between
-f[no-]PICand-f[no-]picbut it's irrelevant here.