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.