"No Such File or Directory" Error When Executing a Binary

No such file or directory error when executing a binary

The answer is in this line of the output of readelf -a in the original question

  [Requesting program interpreter: /lib/ld-linux.so.2]

I was missing the /lib/ld-linux.so.2 file, which is needed to run 32-bit apps. The Ubuntu package that has this file is libc6-i386.

No such file or directory error when trying to execute a binary

1) You're using the wrong calling convention for printf. The arguments were passed in registers, not on the stack: https://en.wikipedia.org/wiki/X86_calling_conventions#System_V_AMD64_ABI. Also, printf needs a value in EAX (0 in your case).

2) When the program starts, there is no return address on the stack. Look here: http://www.dreamincode.net/forums/topic/285550-nasm-linux-getting-command-line-parameters. Therefor,

mov rax,0   
ret

is wrong. But if you use the 64-bit-Linux-syscall

mov edi, 0                  ; return 0 (success)
mov eax, 60 ; sys_exit
syscall

you will not see the output of printf, because it is buffered and the buffer won't be flushed. You can call fflush(0) or exit.

3) To use C functions in Linux you have to link with a special loader (/lib64/ld-linux-x86-64.so.2). I just don't know if it is installed by default.

4) push val1 pushes the address of val1, not its value. Use brackets to get the values. I guess you wanted just load a 32-bit DWORD into a 64-bit register. You can directly load the DWORD into a 32-bit register (the upper part of the 64-bit-register will be cleared) or use movsx for a signed operation.

Quintessence:

section .data

fmt db `%d\n`,0 ; backticks for '\n'
val1 dd 23
val2 dd 9
val3 dd 7

section .text
global _start
extern printf, exit

_start:

movsx rax, dword [val1] ; signed dword to signed qword
movsx rbx, dword [val2]
imul rax, rbx

mov ebx, [val3] ; unsigned dword into RBX
add rax, rbx
mov [val1], rax

mov rdi, fmt ; string pointer
mov rsi, [val1] ; immediate value
xor eax, eax ; no vector registers used
call printf

xor edi, edi
call exit

nasm -f elf64 test64.asm

ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o test64 test64.o -lc

./test64

No such file or directory: Cannot execute but is visible to ls, file and tab-completion

If you try to run an executable and you get the "no such file or directory" error, this often means that the executable is unable to find the correct dynamic loader. If you look at the output from the file command, you see:

...interpreter /lib64/ld-lsb-x86-64.so.3...

Does your system have /lib64/ld-lsb-x86-64.so.3? If not, that suggests that these binaries were built for a different architecture (e.g., 64 bit vs 32 bit) or for a different version of the C library (glibc).

Solutions include:

  • Install packages that contain the necessary interpreter.

  • Find a set of executables that have been compiled for the version of the C library installed on your system.

  • Run things inside a Docker container or chroot environment that has the appropriate C library installed.

A hacky solution would be to use the patchelf command to change the interpreter path embedded in the binaries. Depending on your environment, that might work or it just may make everything crash.

Also, just symlinking from the .so.2 to .so.3 might work.

No such file or directory but it exists

This error can mean that ./arm-mingw32ce-g++ doesn't exist (but it does), or that it exists and is a dynamically linked executable recognized by the kernel but whose dynamic loader is not available. You can see what dynamic loader is required by running ldd /arm-mingw32ce-g++; anything marked not found is the dynamic loader or a library that you need to install.

If you're trying to run a 32-bit binary on an amd64 installation:

  • Up to Ubuntu 11.04, install the package ia32-libs.
  • On Ubuntu 11.10, install ia32-libs-multiarch.
  • Starting with 12.04, install ia32-libs-multiarch, or select a reasonable set of :i386 packages in addition to the :amd64 packages.

`bash: ./a.out: No such file or directory` on running executable produced by `ld`

Link dynamic executables with gcc foo.o (to use the right paths for CRT and libc, and the dynamic linker / ELF interpreter ld-linux-x86-64.so.2).

Or gcc -nostartfiles foo.o for libc but not CRT _start, if you have a hand-written _start

(For static executables without libc or CRT, you can use ld directly or gcc -nostdlib -static.)

gcc -v foo.o will show you the actual paths GCC used on your system.


The other answers only address how to avoid this1, not the actual question of what happened.

The gcc -c a.c; ld -lc a.o commands you gave produce a pretty obvious warning:

ld: warning: cannot find entry symbol _start; defaulting to 0000000000400260

So even if this file could be executed, it will probably crash right away. See @EmployedRussian's answer for an explanation of what you should have done.



The question of why it can't even be executed is still interesting:

$ strace ./a.out 
execve("./a.out", ["./a.out"], [/* 72 vars */]) = -1 ENOENT (No such file or directory)

execve(2) returns ENOENT because it can't find the interpreter (which I figured out from file and so on, see below). You'd get the same error from trying to run a file that started with

#!/usr/non-existant-path/bin/bash

As you discovered, the usual reason for this error message is when running an ELF binary on a system without the right dynamic linker and dynamic libraries installed (e.g. a 64bit system without 32bit support installed). In your case, it's because you used a bad link command and made a dynamic executable with a bad interpreter path.


I'm on Ubuntu 15.10, where GNU file version 5.22 reports:

a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, not stripped

There is no /lib/ld64.so.1 on my system. ldd output is confusing, because ldd uses its default ELF interpreter, not the one specified by the binary.

$ ldd a.out
linux-vdso.so.1 => (0x00007ffc18d2b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0e0a79f000)
/lib/ld64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x0000559dbc9d2000)

So it assumes that the runtime interpreter in the binary resolved to the one ldd used itself, I guess.

Your ldd output is probably from an old version too, since it just shows /lib64/ld-linux-x86-64.so.2 for that line. Not taking a bad guess is probably better behaviour, for a weird case like this, but doesn't help you see that your binary has a weird interpreter path.

readelf -l a.out

will decode the ELF headers for you, including the interpreter path. (Thanks to @EmployedRussian's comment for pointing this out.)

No such file or directory on any executable file in docker

The program binary itself is (in most cases) not self-sufficient; instead, it depends on a number of dynamic libraries (usually at least a C standard library) and a dynamic linker (also known as the interpreter), which knows how to load the binary into the memory and to link it with these libraries.

The information about what linker the system has to use to launch the specific program and which libraries the program requires is stored inside the program binary itself. You may easily extract this information using tools like ldd and readelf. For example, this is how you may find all the stuff /bin/ls needs to run successfully:

$ ldd /bin/ls
linux-vdso.so.1 (0x00007ffec7b46000)
libcap.so.2 => /usr/lib/libcap.so.2 (0x00007f805384c000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f8053642000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f80538ae000)

Or, more verbosely:

$ readelf -a /bin/ls
...
Program Headers:
Type Offset VirtAddr PhysAddr
...
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
...
Dynamic section at offset 0x22a58 contains 28 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libcap.so.2]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]

Note: my examples are taken from Arch box, so your results may be different, yet close to this. The main point here is that the binary relies on ld-linux, which is true for both Arch and Ubuntu (see below).

When you ask the kernel to execute ls, it reads the program binary, looks for the linker the program requires (/lib64/ld-linux-x86-64.so.2) in the filesystem and runs it. The linker then loads ls and all its dependencies into the memory; only after this the code of ls itself is executed.

The problem is that different Linux distributions (and different versions of them) have different environments. While it is common for distros to use GNU libc (glibc) as the C standard library and its ld-linux as the linker, there also are distros using other libc variants and other linkers. Alpine is one of such distros: it uses musl libc and its own linker ld-musl:

$ docker run -it alpine
/ # ldd /bin/ls
/lib/ld-musl-x86_64.so.1 (0x7f40c772d000)
libc.musl-x86_64.so.1 => /lib/ld-musl-x86_64.so.1 (0x7f40c772d000)

This means that Alpine does not have /lib64/ld-linux-x86-64.so.2 file (by default; see Running glibc programs). That is why running ls built for glibc-based system (Ubuntu in your case) inside an Alpine container fails: the kernel reads the binary, learns that it needs /lib64/ld-linux-x86-64.so.2 to load this program, and finds no such file inside the filesystem.

When the kernel is unable to find the interpreter requested by the program, it returns the same error as when you ask it to execute the non-existent file:

man 2 execve
...
ENOENT The file pathname or a script or ELF interpreter does not exist.

This is why you get no such file or directory, which is somewhat misleading, as it does not say which file is not found — the linker, not the program itself.

Given that ls does not have lots of dependencies, chances are good that the trick you try to do will work with containers having glibc-based systems inside:

$ docker run -it -v /bin/ls:/test/ls alpine /test/ls
exec /test/ls: no such file or directory

...

$ docker run -it -v /bin/ls:/test/ls ubuntu /test/ls
bin dev home lib32 libx32 mnt proc run srv test usr
boot etc lib lib64 media opt root sbin sys tmp var

...

$ docker run -it -v /bin/ls:/test/ls archlinux /test/ls
bin dev home lib64 opt root sbin sys tmp var
boot etc lib mnt proc run srv test usr

However, running host binaries inside the container is not what you are supposed to do and there is no guarantee that things won't go haywire, so make sure you really know what you do when employing such tricks.



Related Topics



Leave a reply



Submit