"sh: ./<file> not found" error when trying to execute a file
Asked Answered
L

1

7

I've come across a weirdest problem I ever met. I'm cross-compiling an app for ARM CPU with Linux on-board. I'm using buildroot, and all goes well until I'm trying to run the application on the target: I'm getting -sh: ./hw: not found. E.g.:

$ cat /tmp/test.cpp 
#include <cstdio>
#include <vector>

int main(int argc, char** argv){
        printf("Hello Kitty!\n");
        return 0;
}
$ ./arm-linux-g++ -march=armv7-a /tmp/test.cpp -o /tftpboot/hw

load the executable to the target; then issuing on the target:

# ./hw
-sh: ./hw: Permission denied
# chmod +x ./hw
# ./hw
-sh: ./hw: not found
# ls -l ./hw
-rwxr-xr-x    1 root     root          6103 Jan  1 03:40 ./hw

There's more to it: upon building with distro compiler, like arm-linux-gnueabi-g++ -march=armv7-a /tmp/test.cpp -o /tftpboot/hw, the app runs fine!

I compared executables through readelf -a -W /tftpboot/hw, but didn't notice much defference. I pasted both outputs here. The only thing I noticed, are lines Version5 EABI, soft-float ABI vs Version5 EABI. I tried removing the difference by passing either of -mfloat-abi=softfp and -mfloat-abi=soft, but compiler seems to ignore it. I suppose though, this doesn't really matter, as compiler doesn't even warn.

I also thought, perhaps sh outputs this error if an executable is incompatible in some way. But on my host PC I see another error in this case, e.g.:

$ sh /tftpboot/hw
/tftpboot/hw: 1: /tftpboot/hw: Syntax error: word unexpected (expecting ")")
Luge answered 7/7, 2014 at 9:13 Comment(1)
similar #14536397Hydrastinine
F
11

sh prints this weird error because it is trying to run your program as a shell script!

Your error ./hw: not found is probably caused by the dynamic linker (AKA ELF interpreter) not being found. Try compiling it as a static program with -static or running it with your dynamic loader: # /lib/ld-linux.so.2 ./hw or something like that.

If the problem is that the dynamic loader is named differently in your tool-chain and in your runtime environment you can fix it:

  • In the runtime environment: with a symbolic link.
  • In the tool-chain: use -Wl,--dynamic-linker=/lib/ld-linux.so.2
Freida answered 7/7, 2014 at 9:19 Comment(5)
Yes, the -static option did the trick! Thank you very much! Just curious -- if you know, please, tell me: what the library should've been linked there, and why the file have been treated like a script till I linked statically? Isn't the system see the "ELF" signature in the file?Luge
@YagamyLight: The problem is not the library but the dynamic linker, that is the program that loads dynamic executables. In Linux it is usually /lib/ld-linux*. You can see what it is with objdump -s -j /bin/ls, being /bin/ls a dynamic executable that does work.Freida
@YagamyLight: The file is treated as a script because that is what sh does with its first argument: treat it as a script. To treat it as a command (and possible a program) use sh -c ./hw. But then, you can simply write ./hw.Freida
But I still don't understand: the sh calls the dynamic loader, right? How this could be statically linked into the file, if in this case in order to load the file, we need linker, but the linker is rest in the file, so the file can't be loaded.Luge
@YagamyLight: No, the program has the name of the dynamic linker, set by the --dynamic-linker linker option. The real dynamic linker is in a file in your system. And sh does not call the dynamic loader, it calls the kernel to exec() the program, the kernel sees that it is an ELF file (the signature), checkes whether it has an interpreter or not (the interpreter is almost always the dynamic loader, if present), and if so runs the interpreter instead. If the dynamic linker that your program refers to does not exist you'll have a file not found error.Freida

© 2022 - 2024 — McMap. All rights reserved.