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
Rename All Files in a Folder With a Prefix in a Single Command
How to Remove Cached Credentials from Git
How to Use Sed to Extract Substring
How to Fix Java.Lang.Module.Findexception: Module Java.Se.Ee Not Found
How to Prevent a Background Process from Being Stopped After Closing Ssh Client in Linux
What Does Set -E Mean in a Bash Script
How to Pass Command Output as Multiple Arguments to Another Command
Python Code to Check If Service Is Running or Not.
How to Tar a Directory Without Retaining the Directory Structure
How to Find Which Position a Word Is in a String
How to Set Environment Variables That Crontab Will Use
How to Find All Files Containing Specific Text on Linux
How to Write a Bash Script to Restart a Process If It Dies
Mount Smb/Cifs Share Within a Docker Container
How to Display Number to Two Decimal Places in Bash Function
How to Find Certain Character Position in Shell
How to Write Data to Existing Process'S Stdin from External Process
Separately Redirecting and Recombining Stderr/Stdout Without Losing Ordering