-ENOENT, but believe me, it's there
Almost every ELF-file in a Linux environment is dynamically linked, and the operating system has to locate all dynamic libraries in order to execute the file. To its help, it has the runtime dynamic linker, whose only job is to interpret the ELF file format, load the shared objects with unresolved references, and, at last, execute and pass over the control to the ELF file.
The expected path to the dynamic linker is hardcoded into the ELF itself, so if the linker is missing, it leads to an obvious but maybe confusing error.
If I want to run an executable that has its path to a dynamic linker that simple does not exists, we got this
1root@cgtqmx6:/# ./01_SimpleTriangle -sh:
2./01_SimpleTriangle: No such file or directory
Hue? But the file does exist! OK, lets find out which system calls is made.
1root@cgtqmx6:/# strace ./01_SimpleTriangle
2
3execve("./01_SimpleTriangle", ["./01_SimpleTriangle"], [/* 15 vars */]) = -1 ENOENT (No such file or directory)
4write(2, "strace: exec: No such file or directory) = 40
5exit_group(1) = ?+++ exited with 1 +++
Not much valuable information. Strace calls execve that says the file does not exist. We are talking about the file... but which file is it?
As told before, the runtime dynamic linker is always executed first to load libraries for unresolved symbols. So one qualified guess is that it's the dynamic linker that is missing.
Readelf is a handy tool to read out information from an ELF file such as sections, which architecture it's compiled for and so on. It also shows us the expected path to the dynamic linker.
1root@cgtqmx6:/# readelf -l 01_SimpleTriangle
2
3Elf file type is EXEC (Executable file)
4Entry point 0x9288There are 8 program headers, starting at offset 52
5Program Headers: Type Offset VirtAddr PhysAddr
6FileSiz MemSiz Flg Align
7EXIDX 0x0022ec 0x0000a2ec 0x0000a2ec 0x00088 0x00088 R 0x4
8PHDR 0x000034 0x00008034 0x00008034 0x00100 0x00100 R E 0x4
9INTERP 0x000134 0x00008134 0x00008134 0x00013 0x00013 R 0x1
10>>>>>> [Requesting program interpreter: /lib/ld-linux.so.3] <<<<<<<
11LOAD 0x000000 0x00008000 0x00008000 0x02378 0x02378 R E 0x8000
120x002378 0x00012378 0x00012378 0x002a0 0x00358 RW 0x8000
13DYNAMIC 0x002384 0x00012384 0x00012384 0x00118 0x00118 RW 0x4
14NOTE 0x000148 0x00008148 0x00008148 0x00020 0x00020 R 0x4
15GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
16
17Section to Segment mapping:
18Segment Sections...
1900 .ARM.exidx
2001
2102 .interp
2203 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .ARM.extab .ARM.exidx .eh_frame
2304 .init_array .fini_array .jcr .dynamic .got .data .bss
2405 .dynamic
2506 .note.ABI-tag
2607
Here we go! The expected path is /lib/ld-linux.so.3. Our system is currently using /lib/ld-linux-armhf.so.3, so lets create a symbolic link for now.
1ln -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3
And finally, the program is now executing!
1root@cgtqmx6:/# ./01_SimpleTriangle
2root@cgtqmx6:/#
Anyway, who decide which runtime dynamic linker to use? It's decided in the linker-stage, usually by ld or gcc and may vary between different toolchains,