-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:
root@cgtqmx6:/# ./01_SimpleTriangle -sh: ./01_SimpleTriangle: No such file or directory
Hue? But the file does exist! OK, lets find out which system calls is made.:
root@cgtqmx6:/# strace ./01_SimpleTriangle execve("./01_SimpleTriangle", ["./01_SimpleTriangle"], [/* 15 vars */]) = -1 ENOENT (No such file or directory) write(2, "strace: exec: No such file or directory) = 40 exit_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 is 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 is compiled for and so on. It also shows us the expected path to the dynamic linker.:
root@cgtqmx6:/# readelf -l 01_SimpleTriangle Elf file type is EXEC (Executable file) Entry point 0x9288There are 8 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align EXIDX 0x0022ec 0x0000a2ec 0x0000a2ec 0x00088 0x00088 R 0x4 PHDR 0x000034 0x00008034 0x00008034 0x00100 0x00100 R E 0x4 INTERP 0x000134 0x00008134 0x00008134 0x00013 0x00013 R 0x1 >>>>>> [Requesting program interpreter: /lib/ld-linux.so.3] <<<<<<< LOAD 0x000000 0x00008000 0x00008000 0x02378 0x02378 R E 0x8000 0x002378 0x00012378 0x00012378 0x002a0 0x00358 RW 0x8000 DYNAMIC 0x002384 0x00012384 0x00012384 0x00118 0x00118 RW 0x4 NOTE 0x000148 0x00008148 0x00008148 0x00020 0x00020 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 Section to Segment mapping: Segment Sections... 00 .ARM.exidx 01 02 .interp 03 .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 04 .init_array .fini_array .jcr .dynamic .got .data .bss 05 .dynamic 06 .note.ABI-tag 07
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.:
ln -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3
And finally, the program is now executing!:
root@cgtqmx6:/# ./01_SimpleTriangle root@cgtqmx6:/#
Anyway, who decide which runtime dynamic linker to use? It is decided in the linker-stage, usually by ld or gcc and may vary between different toolchains,