A position independent ELF executable can be loaded and run from arbitrary address within the virtual address space.
I tried to build below simple program:
pie.c
#include <stdio.h>
void main(void)
{
printf("hello, pie!\n");
}
Build command:
gcc pie.c -o pie -pie
The ELF header of the executable is:
pie:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x530 <================= FIXED entry point
Start of program headers: 64 (bytes into file)
Start of section headers: 6440 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
So the entry point address is fixed.
And it is the symbol _start there:
0000000000000530 T _start
So it means the _start must be placed at 0x530.
Isn't this contradictory to being position independent?
ADD 1 - 10:44 AM 8/16/2021
I tried to build the same program without the -pie flag:
gcc pie.c -o pie_not
The generated ELF header is:
pie_not:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x530 <============ Still the same value as with -pie flag
Start of program headers: 64 (bytes into file)
Start of section headers: 6440 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
And I further compared the built results pie and pie_not. Their binaries are identical.
So how could the operating system tell which one should be treated as position independent code??
ADD 2 - 10:56 AM 8/16/2021
I guess I figured it out.
It seems gcc use -pie by default. To avoid it, I have to add -no-pie flag explicitly.
gcc pie.c -o pie_not -no-pie
And the generated ELF header is like this:
pie_not:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file) <==== File type also changed!!!
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400400 <===== Entry point address changed!
Start of program headers: 64 (bytes into file)
Start of section headers: 6376 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
I believe the loader relies on the Type filed in ELF header to decide how to treat the binary.