0

I am trying to understand the difference between PIC (Position-independent code) and no PIC code.

The test code is here.

#include <stdio.h>

int global;
int f() { return global; }

My OS is Ubuntu.

$ uname
Linux

The compiled assembly code is the following. I am not very familiar with assembly code. Could anybody help me understand the difference in light of PIC? Thanks.

$ cat main.sh
#!/usr/bin/env bash
# vim: set noexpandtab tabstop=2:

set -v
function cmd {
diff <($CC -S -fno-pic f.c -c -o -) <($CC -S -fPIC f.c -c -o -)
}

CC=clang cmd
CC=gcc cmd
$ ./main.sh
function cmd {
diff <("$CC" -S -fno-pic f.c -c -o -) <("$CC" -S -fPIC f.c -c -o -)
}

CC=clang cmd
"$CC" -S -fPIC f.c -c -o -
"$CC" -S -fno-pic f.c -c -o -
14c14,15
<     movl    global, %eax
---
>     movq    global@GOTPCREL(%rip), %rax
>     movl    (%rax), %eax
CC=gcc cmd
"$CC" -S -fPIC f.c -c -o -
"$CC" -S -fno-pic f.c -c -o -
14c14,15
<     movl    global(%rip), %eax
---
>     movq    global@GOTPCREL(%rip), %rax
>     movl    (%rax), %eax

Here is another test code f3.c.

#include <stdio.h>

int global;
int *f3() { return &global; }
$ ./main.sh
function cmd {
diff <("$CC" -S -fno-pic f3.c -c -o -) <("$CC" -S -fPIC f3.c -c -o -)
}
CC=clang cmd f3.c
"$CC" -S -fPIC f3.c -c -o -
"$CC" -S -fno-pic f3.c -c -o -
14c14
<   movabsq $global, %rax
---
>   movq    global@GOTPCREL(%rip), %rax
CC=gcc cmd f3.c
"$CC" -S -fno-pic f3.c -c -o -
"$CC" -S -fPIC f3.c -c -o -
14c14
<   movl    $global, %eax
---
>   movq    global@GOTPCREL(%rip), %rax
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
user1424739
  • 11,937
  • 17
  • 63
  • 152
  • Both versions happen to be position independent in this case, but one goes through the GOT (used in shared libraries). – Jester Jan 24 '19 at 17:10
  • So -fno-pic doesn’t really generate no PIC code. How to generate non PIC code then? – user1424739 Jan 24 '19 at 17:15
  • It doesn't forcibly turn PIC off in cases where the PIC version isn't any worse. You can try with different program. For my compiler, indexing an array using a variable shows difference. E.g. `int f(int i) { return global[i]; }` You can even get 3 versions (pie, PIC, plain) – Jester Jan 24 '19 at 17:31
  • Ask the compiler to emit code for `int *get_addr(){return &global;}`. With `-fno-pie` / `-no-pic`, you'll get `mov $global, %eax` (32-bit absolute address) on targets like Linux where the default position-dependent code model guarantees static addresses are in the low 31 bits of address space, so zero- and sign-extended absolute addresses can be used. Or index a static array. See [ELF Shared Object in x86-64 Assembly language](https://stackoverflow.com/q/9341212) and [Mach-O 64-bit format does not support 32-bit absolute addresses. NASM Accessing Array](https://stackoverflow.com/q/47300844) – Peter Cordes Jan 24 '19 at 17:34
  • I think my recent edit on that first Q&A actually made it answer everything you're asking. But see also [32-bit absolute addresses no longer allowed in x86-64 Linux?](https://stackoverflow.com/q/43367427) – Peter Cordes Jan 24 '19 at 17:37
  • I don't think this is a duplicate. My question is specific to PIC. The links that you refers mentions too many stuffs that are not directly related to PIC. I'd like to understand PIC first before moving on to more advanced stuffs. – user1424739 Jan 24 '19 at 17:47
  • `movl $global, %eax` uses a 32-bit absolute address, instead of a RIP-relative LEA or a load from the GOT. The complicated stuff about `-fPIC` is symbol interposition, not actually position-independence (which is fairly straightforward on x86-64), so you can't avoid "advanced stuff" if you really want to ask about `-fPIC`. Compare `-fPIE` vs. `-fno-pie` for just position-independence without symbol interposition. – Peter Cordes Jan 24 '19 at 17:52
  • But fair enough, this might not be exactly a duplicate. – Peter Cordes Jan 24 '19 at 17:54
  • What is GOT? LEA? PIP? – user1424739 Jan 24 '19 at 17:54
  • GOT is global offset table. LEA is an instruction, load effective address. PIP .. nobody mentioned that :) PIE is position independent executable. – Jester Jan 24 '19 at 18:49
  • I mean RIP instead of PIP. Sorry for the typo. – user1424739 Jan 24 '19 at 18:51
  • Could you unclose it? – user1424739 Jan 24 '19 at 18:51
  • RIP is the 64 bit instruction pointer. Do you have a specific question not yet answered? – Jester Jan 24 '19 at 18:54

0 Answers0