file
5.36 says it clearly
file
5.36 actually prints it clearly if the executable is PIE or not. For example, a PIE executable shows as:
main.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, not stripped
and a non-PIE one as:
main.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
The feature was introduced in 5.33 but it did just a simple chmod +x
check. Before that it just printed shared object
for PIE.
In 5.34, it was meant to start checking the more specialized DF_1_PIE
ELF metadata, but due to a bug in the implementation it actually broke things and showed GCC PIE executables as shared objects
.
I have interpreted file
source code, including the bug, and exactly which bytes of the ELF format it checks in excruciating detail at: https://stackoverflow.com/questions/34519521/why-does-gcc-create-a-shared-object-instead-of-an-executable-binary-according-to/55704865#55704865
A quick summary of file 5.36 behavior is:
- if
Elf32_Ehdr.e_type == ET_EXEC
- else if
Elf32_Ehdr.e_type == ET_DYN
- if
DT_FLAGS_1
dynamic section entry is present
- if
DF_1_PIE
is set in DT_FLAGS_1
:
- else
- else
- if file is executable by user, group or others
- else
GDB run the executable twice and see ASLR
One very direct thing that you can do is to run the executable twice through GDB and see if the address changes across runs due to ASLR.
I have explained how to do that in detail at: https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031#51308031
While this is not necessarily the most practical solution and not possible if you don't trust the executable, it is fun and it does the ultimate check that we really care about, which is if the Linux kernel / dynamic loader changes the executable location or not.
-pie -fpie
special compiler flags to compile a program as a PIE. That link had other interesting information, though -- thank you!