3

I don't find any useful information on the differences between "-fno-pie" and "-no-pie". Are they gcc flags or ld flags? Are they both necessary or not?

I found a piece of makefile that uses these lines:

CC = @gcc -fno-pie -no-pie
LD = @gcc -fno-pie -no-pie

So it uses gcc for linking instead of a direct call to ld but I don't understand the differences between the flags and if they are both necessary to compiling and linking stage

Francesco
  • 523
  • 4
  • 25

1 Answers1

3

TLDR; -fno-pie is a "code generation option" while -no-pie is a "linker option". You need both.

-fno-pie tell GCC that you don't want to make a PIE. If you are not making a PIE you are making either a shared object (using -shared) or an ordinary executable.
Ordinary executables are loaded below the 4GiB and at a fixed address, furthermore their symbols cannot be interposed so -fno-pie tell GCC that can translate an expression like &foo in something like mov eax, OFFSET FLAT foo.
It doesn't have to use the GOT since the symbols are not interposed and it doesn't have to use RIP-relative addressing since a 32-bit address fits in the 32-bit immediate/displacement of x86-64 instructions.

Check out what -fpie/-fno-pie do in terms of assembly instructions.

An instruction like mov eax, OFFSET FLAT foo creates a R_X86_64_32 relocation, this relocation is used in 64-bit programs when the compiler is sure that an address will always fit 32 bits (i.e. is below 4GiB).
However -fno-pie doesn't stop GCC from passing -pie to the linker.
So the linker sees a R_X86_64_32 relocation and is still instructed to make a PIE executable. The relocation promises that the address will be below 4GiB but the -pie flag promises that the executable is meant to be loaded anywhere, including above 4GiB.
These contrast each other and the linker is required to check this stalemate and produce an error.

To tell the linker that indeed you did not want to link a PIE executable, you need to pass -no-pie to GCC.

You can pass -v to GCC while compiling a file to see what options are passed to collect2 (a wrapper to the linker).
Regardless of the presence of -fno-pie, -pie is still passed to collect2.
Adding -no-pie to GCC will suppress -pie in the collect2 command line.

Note: Older distributions built GCC without defaulting to -fpie -pie.

Margaret Bloom
  • 41,768
  • 5
  • 78
  • 124
  • It might be more clear to say that `-fpie` is a "code generation option" (like most `-f` options are), and `-pie` is a "linking option" (does not affect generated assembly, just passed through by the compiler driver to the linker). – amonakov May 05 '23 at 13:02
  • Based on **TLDR;** what I need is `CC = @gcc -fno-pie` and `LD = @gcc -no-pie`, isn't it? So I don't need both in the 2 script lines – Francesco Aug 30 '23 at 06:34