27

I read this post on PIC and it seems that it always be good to use PIC (whenever it is exe / static / share llibrary).

So what are the disadvantages?
Are there examples elaborating when not to use PIC?

Community
  • 1
  • 1
Azil
  • 457
  • 2
  • 5
  • 10
  • 1
    PIC generally can't be used in Windows because DLL addresses are fixed during load time. Moreover in x86 PIC is not as efficient as in x86_64 – phuclv Jul 10 '15 at 04:32

2 Answers2

16

The accepted answer in the linked question is very simplistic, and only brings up one thing that differs between PIC and non-PIC code, generation of jumps that are relative instead of absolute.

When you make PIC code, it's not only the code that's position independent, it's the data as well. And not all code or data can be addressed simply by using relative offsets, it has to be resolved at load-time (when the library/program is loaded into memory) or even during run-time.

Also, using relative addressing means that the CPU has to translate the relative offsets into absolute addresses, instead of it being done by the compiler.

On system with virtual memory there's often no need to spend load- or run-time on these relative address resolutions when the compiler can do it once and for all.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Is there a situation of using -fpic, or not using fpic that the program will crash ? (does the compiler generate suitable machine code for both cases ?) – Azil Jul 10 '15 at 04:38
  • 1
    @Azil: It does generate the proper code. If you're building a shared library (.so, .dll), you *must* use PIC, it doesn't work otherwise. Some machines like the Amiga for example had *all* code being PIC due to their architecture, but then those were running on *real* CPUs (68k) that didn't suffer from it. ;-) – DevSolar Jul 10 '15 at 04:54
  • So, building so (dll) without PIC - always give compilation error ? – Azil Jul 10 '15 at 05:03
  • 1
    @Azil Maybe not compiler error, because the compiler doesn't actually know that you're building a DLL, however you will most likely get linker errors. – Some programmer dude Jul 10 '15 at 06:06
  • @JoachimPileborg: Well, MSVC gets `DynamicLibrary<...>` as a hint, and GCC gets `-shared`, at least if you're doing it right. ;-) – DevSolar Jul 10 '15 at 13:43
  • @DevSolar "Dynamic-link libraries (DLLs) in Microsoft Windows do not use a global offset table for linkage between routines inside a given DLL or executable, and ***do not generally use position-independent code***. As a result, their routines cannot be overridden by previously loaded DLLs, and the code has to be relocated by the operating system after it has been loaded into memory." https://en.wikipedia.org/wiki/Position-independent_code#Windows_DLLs – phuclv Jul 12 '15 at 04:24
  • @LưuVĩnhPhúc: You caught me oversimplifying a bit. DLL's don't generally use *position-independent* code, but they need to be *relocatable*, i.e. you still need "special" code generated by the compiler. – DevSolar Jul 13 '15 at 06:47
  • You can use non PIC objects in shared libraries. Your code segment will then be duplicated in each use case. Windows did get around the whole problem because they dont allow variables be exported from DLLs and there is no performance penalty at runtime (only at startup time) for relocating functions. I think Microsoft did it much better and without doubt much faster. I don't know if in the meantime they have added the feature of exporting variables from DLL and what the performance impact maybe. – Lothar Oct 19 '17 at 20:40
4

On some architectures, including x86, -fPIC generates much worse code (i.e. a function call) for loads/stores of data. While this is tolerable for libraries, it is undesirable for executables.

One of the major selling points of the amd64 instruction set (and also the recent gnu-x32 ABI) was the addition of "PC-relative load/store" instructions, which solve the efficiency problem.

Note that hardened systems usually do enable -fPIE for all executables, because it allows address-space layout randomness.

o11c
  • 15,265
  • 4
  • 50
  • 75
  • It's not comparable to a function call, but it takes up a register. – DevSolar Jul 10 '15 at 04:38
  • @DevSolar uh, it definitely requires a function call (although it may cache it in a register after the first time obviously). It shows up in disassembly with names like `__x86.get_pc_thunk.cx`, obviously the register varies depending on what is currently in use. – o11c Jul 10 '15 at 11:29
  • 3
    Ah... we mean the same thing. The "function call" is a trick to get the address of the offset table into a register. Keeping it cached takes up a register (as I said), not caching it makes data access require a function call (as you said). It should be noted that this is one of the typical "ugly bits" of the x86 architecture; most if not all other CPU families allowed proper PC-relative addressing back in the 1980's... – DevSolar Jul 10 '15 at 13:35
  • @DevSolar: yep, PC-relative addressing was available on the PDP-11, even in the '70s. The addressing modes were beautifully designed. –  Jun 01 '22 at 07:16