"No such file or directory" error when running a dynamically-linked ARM executable - linux

I am cross-compiling for an ARM embedded Linux platform running Ubuntu 15.04. Previous, statically-linked, versions of this program have run just fine. Recently I needed to link in libproprietary (lib name changed for this question), which is only available as an .so.
libproprietary.so works; I am able to run a different program that depends on it.
$ uname -a
Linux <hostname> 3.10.92-71 #1 SMP PREEMPT Fri Dec 18 00:38:54 BRST 2015 armv7l armv7l armv7l GNU/Linux
The problem:
$ ./myprogram
-bash: ./myprogram: No such file or directory
What I've tried:
$ ldd ./myprogram
libproprietary.so.2 => /usr/lib/libproprietary.so.2 (0xb6bbc000)
librt.so.1 => /lib/arm-linux-gnueabihf/librt.so.1 (0xb6ba6000)
libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6b92000)
libusb-1.0.so.0 => /lib/arm-linux-gnueabihf/libusb-1.0.so.0 (0xb6b72000)
libstdc++.so.6 => /usr/lib/arm-linux-gnueabihf/libstdc++.so.6 (0xb6ab8000)
libm.so.6 => /lib/arm-linux-gnueabihf/libm.so.6 (0xb6a43000)
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6955000)
/usr/lib/ld.so.1 => /lib/ld-linux-armhf.so.3 (0xb6f28000)
libgcc_s.so.1 => /lib/arm-linux-gnueabihf/libgcc_s.so.1 (0xb692c000)
libudev.so.1 => /lib/arm-linux-gnueabihf/libudev.so.1 (0xb690f000)
$ file ./myprogram
./myprogram: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=881d76b2ce20f32aef95796b4fee9f01e492a7d2, not stripped
$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=a687c2baf9963c62c6abd209863d360dd0863686, stripped
$ readelf -l myprogram| grep interpreter
[Requesting program interpreter: /usr/lib/ld.so.1]
$ strace ./myprogram
execve("./myprogram", ["./myprogram"...], [/* 21 vars */]) = -1 ENOENT (No such file or directory)
write(2, "strace: exec: No such file or di"..., 40strace: exec: No such file or directory
) = 40
exit_group(1) = ?
+++ exited with 1 +++
$ ls -l myprogram
-rwxrwxr-x [details snipped]
$ file /usr/lib/libproprietary.so.<version>
/usr/lib/libproprietary.so.<version>: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=d9b4ba3b9ec03779792984bc8a89ceede5737455, stripped
It appears that the interpreter, /usr/lib/ld.so.1, does not exist. I'm going to guess that it should be similar to what /bin/ls is using:
$ readelf -l /bin/ls | grep interpreter
[Requesting program interpreter: /lib/ld-linux-armhf.so.3]
I don't know how to fix this in my link step however.
ccache arm-linux-gnueabihf-g++ -o myprogram -static -Wl,--whole-archive -lpthread -Wl,--no-whole-archive -Wl,-no-undefined -pthread -Wl,-Bdynamic -lproprietary -Wl,-rpath-link=result/debug/lib -Wl,-rpath=\$ORIGIN/../../../../result/debug/lib variant-dir/debug/core-.o -Lresult/debug/lib -Wl,-Bstatic -l<other libs>
I did try moving -Wl,-Bdynamic -lproprietary after the core-.o word, but that didn't change anything.

It appears that the interpreter, /usr/lib/ld.so.1, does not exist. I'm going to guess that it should be similar to what /bin/ls is using:
Correct. You could change the interpreter by adding -Wl,--dynamic-linker=/lib/ld-linux-armhf.so.3 flag at link time.
However,
Your toolchain may be targeting a different version of libc from the one you actually have installed (in which case the program will likely crash).
If it is targeting correct libc, then your toolchain is mis-configured.

Related

Why does ld need /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 while its default dynamic linker is /lib64/ld-linux-x86-64.so.2?

In x86-64 target Debian, most of the programs are link against shared objects with the /lib64/ld-linux-x86-64.so.2. And there is also one in /lib/x86_64-linux-gnu/, so I delete it as I thought
it is unnecessary :
rm /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
then test :
gcc test.c
it showed as the following :
/usr/bin/ld: cannot find /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 inside /
collect2: error: ld returned 1 exit status
So , why does ld need to find the /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 while the default dynamic linker is /lib64/ld-linux-x86-64.so.2 when linking ?
/lib64/ is a symlink to /usr/lib64/.
cd /lib64/ && ls -l ld-linux-x86-64.so.2
lrwxrwxrwx 1 root .. ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.28.so
cd /usr/lib/x86_64-linux-gnu/
ls -l ld-linux-x86-64.so.2
lrwxrwxrwx 1 root .. ld-linux-x86-64.so.2 -> ld-2.28.so
The main link to the linker ld-2.28.so is /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 : Do not change it. (The link in /lib64/ and /usr/lib64/ is for compatibility reasons with certain software.)

Newly built gcc not being used even after setting $PATH

My server has GCC4 and I need newer version, so I built GCC7.3.0 and added the path to the $PATH variable. After this, gcc -v and g++ -v points to the correct version:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/users/home/m/GCC-7.3.0/bin/../libexec/gcc/x86_64-pc-linux-gnu/7.3.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /home/m/gccbuild/../srcdir/configure --prefix=/home/m/GCC-7.3.0 --enable-languages=c,c++,fortran,go --disable-multilib
Thread model: posix
gcc version 7.3.0 (GCC)
However, I tried compiling a simple hello.cc program and ldd a.out gives:
linux-vdso.so.1 => (0x00007ffe609bb000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fa0bff67000)
libm.so.6 => /lib64/libm.so.6 (0x00007fa0bfc65000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fa0bfa4f000)
libc.so.6 => /lib64/libc.so.6 (0x00007fa0bf681000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa0c026e000)
From here, was expecting something like:
libstdc++.so.6 => /users/home/m/GCC-7.3.0/lib64/libstdc++.so.6 (0x0000123456789000)
libgcc_s.so.1 => /users/home/m/GCC-7.3.0/lib64/libgcc_s.so.1 (0x0000123456ABC000)
Also, cat /proc/version gives:
Linux version 3.10.0-1127.el7.x86_64 (mockbuild#kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) ) #1 SMP Tue Mar 31 23:36:51 UTC 2020
EDIT:
Output to grep configure config.status within gcc build directory:
# Generated by configure.
# Compiler output produced by configure, useful for debugging
# configure, is in config.log if it exists.
configured by /home/s18002/gccbuild/../srcdir/configure, generated by GNU Autoconf 2.64,
ac_configure_extra_args=
ac_configure_extra_args="$ac_configure_extra_args --silent"
set X '/bin/sh' '/home/s18002/gccbuild/../srcdir/configure' '--prefix=/home/m/GCC-7.3.0' '--disable-multilib' '--enable-languages=c,c++,fortran,go,lto' $ac_configure_extra_args --no-create --no-recursion
"L) $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags --build-includes; else echo -funconfigured-libstdc++-v3 ; fi` -L$$r/$(TARGET_SUBDIR)/li"\
S["extra_host_zlib_configure_flags"]=""
S["extra_host_libiberty_configure_flags"]="--enable-shared"
S["extra_linker_plugin_configure_flags"]=""
S["extra_isl_gmp_configure_flags"]="--with-gmp- builddir=$$r/$(HOST_SUBDIR)/gmp"
S["extra_mpc_mpfr_configure_flags"]="--with-mpfr-include=$$s/mpfr/src --with-mpfr-lib=$$r/$(HOST_SUBDIR)/mpfr/src/.libs"
S["extra_mpc_gmp_configure_flags"]="--with-gmp-include=$$r/$(HOST_SUBDIR)/gmp --with-gmp-lib=$$r/$(HOST_SUBDIR)/gmp/.libs"
S["extra_mpfr_configure_flags"]="--with-gmp-include=$$r/$(HOST_SUBDIR)/gmp --with-gmp-lib=$$r/$(HOST_SUBDIR)/gmp/.libs"
S["extra_liboffloadmic_configure_flags"]=""
S["TOPLEVEL_CONFIGURE_ARGUMENTS"]="/home/s18002/gccbuild/../srcdir/configure --prefix=/home/s18002/GCC-7.3.0 --enable-languages=c,c++,fortran,go --disable-multilib"
# Let's still pretend it is `configure' which instantiates (i.e., don't
configure_input='Generated from '`
`' by configure.'
configure_input="$ac_file. $configure_input"
case $configure_input in #(
ac_sed_conf_input=`$as_echo "$configure_input" |
*) ac_sed_conf_input=$configure_input;;
s|#configure_input#|$ac_sed_conf_input|;t t
The package I was trying to install got installed, which means it is using gcc7. How can I make sure GCC7 is used locally for all my purposes?
Make sure you are compiling with g++ and not gcc:
$ gcc test.c
$ ldd a.out
linux-vdso.so.1 => (0x00007ffcbdd71000)
libc.so.6 => /lib64/libc.so.6 (0x00007f3b23c32000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3b24000000)
$ g++ test.c
$ ldd a.out
linux-vdso.so.1 => (0x00007ffedc577000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f745ed73000)
libm.so.6 => /lib64/libm.so.6 (0x00007f745ea71000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f745e85b000)
libc.so.6 => /lib64/libc.so.6 (0x00007f745e48d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f745f07a000)

Linking: Why does linker not honour symlink to library?

I have the following C program:
#include <stdio.h>
#include <zlib.h>
int main()
{
z_stream strm;
int integer = 0;
scanf("heloworld %d", &integer);
printf("ok\n");
if (integer == 10)
{
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
deflateInit(&strm, 0);
}
return 0;
}
This is a basic helloworld program which uses zlib.
If I search for the libz library, I can find it under /usr/lib/x86_64-linux-gnu/libz.so:
$ ls -lah libz.so
lrwxrwxrwx 1 root root 40 May 20 14:55 libz.so -> /usr/lib/x86_64-linux-gnu/libz.so.1.2.11
and it is pointing to the real version of libz rather than the soname.
I compile it with the following command and check the dependencies:
$ gcc a.c -lz
$ ldd a.out
linux-vdso.so.1 (0x00007ffec44b6000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f6674055000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6673e63000)
/lib64/ld-linux-x86-64.so.2 (0x00007f667408c000)
How is it pointing to libz.so.1 instead of libz.so.1.2.11 (realname) since the symlink of libz.so.1 is pointing there? I am assuming that the linker is using the symlink however this is not the case.
Further to this, if I perform the following command:
$ objdump -p libz.so.1.2.11 | grep SONAME
SONAME libz.so.1
My question is, is it using the symlink name or the SONAME from the file the symlink provides?
If the linker put libz.so.1.2.11 in your executable, then it would break when you updated the library. Instead it puts the major version known to ldconfig in the executable, which is in turn a link to the current installed version.
See ldconfig http://man7.org/linux/man-pages/man8/ldconfig.8.html
I have discovered that under /lib/x86_64-linux-gnu there are two symlinks for libz.so which are:
libz.so
libz.so.1
When I compile, the linker uses the libz.so as a symlink to point to another .so file.
The .so file which libz.so is pointing to contains an SONAME entry which can be viewed as so:
$ objdump -p ./libz.so | grep SONAME
SONAME libz.so.1
Further I can see that the symlink points to libz.so.1.2.11
$ ls -alh libz.so
lrwxrwxrwx 1 root root 36 May 21 00:51 libz.so -> /lib/x86_64-linux-gnu/libz.so.1.2.11
If I edit the .dynstr section of that library like so:
$ sudo objcopy --dump-section .dynstr=/tmp/dyn.dump ./libz.so.1.2.11
# Find the bytes for libz.so.1 and change them to libz.so.2
$ hexedit /tmp/dyn.dump
$ sudo objcopy --update-section .dynstr=/tmp/dyn.dump ./libz.so.1.2.11
and then recompile my binary I notice:
$ ldd a.out
linux-vdso.so.1 (0x00007ffe54bbe000)
libz.so.2 => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f58bb5c7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f58bb7f0000)
Once I create a symlink of libz.so.2 under /lib/x86_64-linux-gnu/libz.so.2 to point to libz.so.1.2.11 I get the following output:
$ ldd a.out
linux-vdso.so.1 (0x00007ffe54bbe000)
libz.so.2 => /lib/x86_64-linux-gnu/libz.so.2 (0x00007f58bb7b9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f58bb5c7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f58bb7f0000)
Therefore to answer my question it is not the symlink which adds an entry in the runtime dependencies of the executable but the SONAME entry in the shared object.

What's the difference between "statically linked" and "not a dynamic executable" from Linux ldd?

Consider this AMD64 assembly program:
.globl _start
_start:
xorl %edi, %edi
movl $60, %eax
syscall
If I compile that with gcc -nostdlib and run ldd a.out, I get this:
statically linked
If I instead compile that with gcc -static -nostdlib and run ldd a.out, I get this:
not a dynamic executable
What's the difference between statically linked and not a dynamic executable? And if my binary was already statically linked, why does adding -static affect anything?
There are two separate things here:
Requesting an ELF interpreter (ld.so) or not.
Like #!/bin/sh but for binaries, runs before your _start.
This is the difference between a static vs. dynamic executable.
The list of dynamically linked libraries for ld.so to load happens to be empty.
This is apparently what ldd calls "statically linked", i.e. that any libraries you might have linked at build time were static libraries.
Other tools like file and readelf give more information and use terminology that matches what you'd expect.
Your GCC is configured so -pie is the default, and gcc doesn't make a static-pie for the special case of no dynamic libraries.
gcc -nostdlib just makes a PIE that happens not to link to any libraries but is otherwise identical to a normal PIE, specifying an ELF interpreter.
ldd confusingly calls this "statically linked".
file : ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2 ...
gcc -nostdlib -static overrides the -pie default and makes a true static executable.
file : ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked ...
gcc -nostdlib -no-pie also chooses to make a static executable as an optimization for the case where there are no dynamic libraries at all. Since a non-PIE executable couldn't have been ASLRed anyway, this makes sense. Byte-for-byte identical to the -static case.
gcc -nostdlib -static-pie makes an ASLRable executable that doesn't need an ELF interpreter. GCC doesn't do this by default for gcc -pie -nostdlib, unlike the no-pie case where it chooses to sidestep ld.so when no dynamically-linked libraries are involved.
file : ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), statically linked ...
-static-pie is obscure, rarely used, and older file doesn't identify it as statically linked.
-nostdlib doesn't imply -no-pie or -static, and -static-pie has to be explicitly specified to get that.
gcc -static-pie invokes ld -static -pie, so ld has to know what that means. Unlike with the non-PIE case where you don't have to ask for a dynamic executable explicitly, you just get one if you pass ld any .so libraries. I think that's why you happen to get a static executable from gcc -nostdlib -no-pie - GCC doesn't have to do anything special, it's just ld doing that optimization.
But ld doesn't enable -static implicitly when -pie is specified, even when there are no shared libraries to link.
Details
Examples generated with gcc --version gcc (Arch Linux 9.3.0-1) 9.3.0
ld --version GNU ld (GNU Binutils) 2.34 (also readelf is binutils)
ldd --version ldd (GNU libc) 2.31
file --version file-5.38 - note that static-pie detection has changed in recent patches, with Ubuntu cherry-picking an unreleased patch. (Thanks #Joseph for the detective work) - this in 2019 detected dynamic = having a PT_INTERP to handle static-pie, but it was reverted to detect based on PT_DYNAMIC so shared libraries count as dynamic. debian bug #948269. static-pie is an obscure rarely-used feature.
GCC ends up running ld -pie exit.o with a dynamic linker path specified, and no libraries. (And a boatload of other options to support possible LTO link-time optimization, but the keys here are -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie. collect2 is just a wrapper around ld.)
$ gcc -nostdlib exit.s -v # output manually line wrapped with \ for readability
...
COLLECT_GCC_OPTIONS='-nostdlib' '-v' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/collect2 \
-plugin /usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/liblto_plugin.so \
-plugin-opt=/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/lto-wrapper \
-plugin-opt=-fresolution=/tmp/ccoNx1IR.res \
--build-id --eh-frame-hdr --hash-style=gnu \
-m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie \
-L/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0 \
-L/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/../../../../lib -L/lib/../lib \
-L/usr/lib/../lib \
-L/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/../../.. \
/tmp/cctm2fSS.o
You get a dynamic PIE with no dependencies on other libraries. Running it still invokes the "ELF interpreter" /lib64/ld-linux-x86-64.so.2 on it which runs before jumping to your _start. (Although the kernel has already mapped the executable's ELF segments to ASLRed virtual addresses, along with ld.so's text / data / bss).
file and readelf are more descriptive.
PIE non-static executable from gcc -nostdlib
$ gcc -nostdlib exit.s -o exit-default
$ ls -l exit-default
-rwxr-xr-x 1 peter peter 13536 May 2 02:15 exit-default
$ ldd exit-default
statically linked
$ file exit-default
exit-default: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=05a4d1bdbc94d6f91cca1c9c26314e1aa227a3a5, not stripped
$ readelf -a exit-default
...
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1000
...
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000001f8 0x00000000000001f8 R 0x8
INTERP 0x0000000000000238 0x0000000000000238 0x0000000000000238
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000000002b1 0x00000000000002b1 R 0x1000
LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000
0x0000000000000009 0x0000000000000009 R E 0x1000
... (the Read+Exec segment to be mapped at virt addr 0x1000 is where your text section was linked.)
If you strace it you can also see the differences:
$ gcc -nostdlib exit.s -o exit-default
$ strace ./exit-default
execve("./exit-default", ["./exit-default"], 0x7ffe1f526040 /* 51 vars */) = 0
brk(NULL) = 0x5617eb1e4000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffcea703380) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9ff5b3e000
arch_prctl(ARCH_SET_FS, 0x7f9ff5b3ea80) = 0
mprotect(0x5617eabac000, 4096, PROT_READ) = 0
exit(0) = ?
+++ exited with 0 +++
vs. -static and -static-pie the first instruction executed in user-space is your _start (which you can also check with GDB using starti).
$ strace ./exit-static-pie
execve("./exit-static-pie", ["./exit-static-pie"], 0x7ffcdac96dd0 /* 51 vars */) = 0
exit(0) = ?
+++ exited with 0 +++
gcc -nostdlib -static-pie
$ gcc -nostdlib -static-pie exit.s -o exit-static-pie
$ ls -l exit-static-pie
-rwxr-xr-x 1 peter peter 13440 May 2 02:18 exit-static-pie
peter#volta:/tmp$ ldd exit-static-pie
statically linked
peter#volta:/tmp$ file exit-static-pie
exit-static-pie: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=daeb4a8f11bec1bb1aaa13cd48d24b5795af638e, not stripped
$ readelf -a exit-static-pie
...
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1000
...
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000229 0x0000000000000229 R 0x1000
LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000
0x0000000000000009 0x0000000000000009 R E 0x1000
... (no Interp header, but still a read+exec text segment)
Notice that the addresses are still relative to the image base, leaving ASLR up to the kernel.
Surprisingly, ldd doesn't say that it's not a dynamic executable. That might be a bug, or a side effect of some implementation detail.
gcc -nostdlib -static traditional non-PIE old-school static executable
$ gcc -nostdlib -static exit.s -o exit-static
$ ls -l exit-static
-rwxr-xr-x 1 peter peter 4744 May 2 02:26 exit-static
peter#volta:/tmp$ ldd exit-static
not a dynamic executable
peter#volta:/tmp$ file exit-static
exit-static: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=1b03e3d05709b7288fe3006b4696fd0c11fb1cb2, not stripped
peter#volta:/tmp$ readelf -a exit-static
ELF Header:
...
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x401000
... (Note the absolute entry-point address nailed down at link time)
(And that the ELF type is EXEC, not DYN)
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000010c 0x000000000000010c R 0x1000
LOAD 0x0000000000001000 0x0000000000401000 0x0000000000401000
0x0000000000000009 0x0000000000000009 R E 0x1000
NOTE 0x00000000000000e8 0x00000000004000e8 0x00000000004000e8
0x0000000000000024 0x0000000000000024 R 0x4
Section to Segment mapping:
Segment Sections...
00 .note.gnu.build-id
01 .text
02 .note.gnu.build-id
...
Those are all the program headers; unlike pie / static-pie I'm not leaving any out, just other whole parts of the readelf -a output.
Also note the absolute virtual addresses in the program headers that don't give the kernel a choice where in virtual address space to map the file. This is the difference between EXEC and DYN types of ELF objects. PIE executables are shared objects with an entry point, allowing us to get ASLR for the main executable. Actual EXEC executables have a link-time-chosen memory layout.
ldd apparently only reports "not a dynamic executable" when both:
no ELF interpreter (dynamic linker) path
ELF type = EXEC

Executable is in current directory but can't be run [duplicate]

This question already has answers here:
Executing 32 bit code under Ubundu 64 bit installation error- No such file or directory
(3 answers)
Closed 7 years ago.
I'm having a weird problem where I have an executable in a directory, but when I try to run it, bash says that it doesn't exist:
kiarashsadr#pandoras-box:~/Downloads/Tether/linux$ ls
adb run.sh
kiarashsadr#pandoras-box:~/Downloads/Tether/linux$ ls -l
total 1204
-rwxrwxr-x 1 kiarashsadr kiarashsadr 1226659 Mar 9 2013 adb
-rwxrwxr-x 1 kiarashsadr kiarashsadr 521 Oct 29 2012 run.sh
kiarashsadr#pandoras-box:~/Downloads/Tether/linux$ ./adb
bash: ./adb: No such file or directory
output from file:
kiarashsadr#pandoras-box:~/Downloads/Tether/linux$ file adb
adb: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.8, not stripped
wut??
You're trying to run a 32-bit executable on a 64-bit system. Bash doesn't differentiate between this case and "no such file or directory" case.
More about this topic: Executing 32 bit code under Ubundu 64 bit installation error- No such file or directory
More on how to run 32-bit executables on 64-bit systems: https://askubuntu.com/questions/454253/how-to-run-32-bit-app-in-ubuntu-64-bit
As stated by VOR73X, the reason in this case is that the file is a 32-bit executable on a 64-bit architecture. You can run it, but you need a compatibility layer to do so. If you have it:
mintaka:/home/lserni # file ansi
ansi: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.2.5, not stripped
mintaka:/home/lserni # uname -a
Linux mintaka 4.0.1-1-default #1 SMP Wed Apr 29 15:04:53 UTC 2015 (e3a374a) x86_64 x86_64 x86_64 GNU/Linux
mintaka:/home/lserni # ./ansi
Syntax: ansi [file|-]
...and otherwise you get 'no such file or directory'.
However, there might be other reasons to be unable to run a file that "seems" to be there (or even is).
Missing dynamic libraries would give a distinctive error (at least they do on my system, Linux OpenSuSE 13.2):
./test: error while loading shared libraries: libcap.so.2: cannot open shared object file: No such file or directory
Another possibility...
...is that the file is not named as you think it is. The file you asked for is really not there!
For example (using the same obsolete file as before)
mintaka:/home/lserni # mv ansi 'ansi '
mintaka:/home/lserni # ls -la ansi*
-rwxr-xr-x 1 root root 14268 Sep 17 23:29 ansi
The file seems to be there but its name now ends with a space, so as you would expect...
mintaka:/home/lserni # ./ansi
bash: ./ansi: No such file or directory
Of course if the file is called correctly, escaping the space...
mintaka:/home/lserni # ./ansi\
Syntax: ansi [file|-]
mintaka:/home/lserni #
Other tricks are possible (I did it to myself once by mistake and have seen some worm using this trick to hide from a casual 'ls'). For example UTF8 invisible characters.
Try
ls -la | hexdump -C
to verify that the name is indeed what it ought to be.

Resources