17

I've got caught in the not-so-sunny world of cross-compilation.

I'm trying to compile a simple hello world application for my BeagleBone Black (which runs a TI Cortex-A8 processor).

First of all, I compiled and ran successfully the hello world application on x86 with gcc

Then I changed my compilation settings to the following:

arm-linux-gnueabi-gcc -c -O0 -g3 -Wall main.c -o bin/obj/main.o
arm-linux-gnueabi-gcc bin/obj/main.o -o bin/hello_world

I transferred the file via SCP to the BeagleBone, and set executable permissions with chmod +x hello_world

Upon running it (./hello_world), my only response is:

-bash: ./hello_world: No such file or directory

The output of file matches that of /sbin/init as I would expect:

$ file hello_world
hello_world: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x24b659b7a41fe043a6f4649d4ebfb5e692ebf0c7, not stripped
$ file /sbin/init
/sbin/init: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xd21f6957ec031a27d567b3d5e6aa14b9e0c30c37, stripped

The result of ldd is:

$ ldd hello_world
    not a dynamic executable

I tried adding a suitable platform and CPU type, changing my compilation to:

arm-linux-gnueabi-gcc -c -O0 -g3 -Wall -march=armv7-a -mtune=cortex-a8  main.c -o bin/obj/main.o
arm-linux-gnueabi-gcc bin/obj/main.o -o bin/hello_world

This initially started giving me a new error: Text file busy, but I have since been unable to get that error back again as it now returns No such file or directory. I'm guessing that particular attempt was just a bad transfer or something.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Chris Watts
  • 6,197
  • 7
  • 49
  • 98
  • p.s. output of `uname -a` is `Linux beaglebone 3.8.13-bone70 #1 SMP Fri Jan 23 02:15:42 UTC 2015 armv7l GNU/Linux` – Chris Watts Aug 10 '15 at 21:02
  • 1
    Are you attempting to run hello_world from a noexec partition? – adelphus Aug 10 '15 at 21:05
  • Have you tried to statically link it? I suspect you don't have the required libs on your BB.. – Eugene Sh. Aug 10 '15 at 21:10
  • Try "strace ./hello_world" to see if that will help you find the missing piece. – Lee Daniel Crocker Aug 10 '15 at 21:16
  • I don't have strace sadly. And I cant connect this BB to the internet to get it. – Chris Watts Aug 10 '15 at 21:17
  • @adelphus I copied `/bin/hostname` to the directory I'm running from, and it executes correctly. – Chris Watts Aug 10 '15 at 21:19
  • I remember compiling strace for for BB, once upon a time... I think it's pretty straightforward. You really don't need an internet on BB for it. And as a general advice, setup an NFS folder on your PC, and share it with BB for the development. It will spare you a hassle of transferring the files back and forth. – Eugene Sh. Aug 10 '15 at 21:20
  • 1
    A common case that gives you these results/error is when you compile/link using a different runtime than your target, and the executable references a dynamic linker that does not exist on your target. e.g. you've linked your executable to glibc, while the target uses uClibc. You can perhaps get more clues if you run your program under strace. To figure out which dynamic linker is used by an executable, run `objdump -j .interp -s ./filename` – nos Aug 10 '15 at 21:26
  • The dynamic linker appears to be `ld-linux.so` from that command. Is this what it should be? I'm trying to compile a mini version of strace as we speak but I can't get it to resolve `sys/reg.h` atm – Chris Watts Aug 10 '15 at 21:33
  • Try `readelf -a` instead of `file` for your executable comparison. Like @nos says, pay particular attention to the INTERP program header. – Nemo Aug 10 '15 at 21:58
  • Okay, so the difference is my program is requesting `/lib/ld-linux.so.3`, but `/sbin/init` requests `/lib/ld-linux-armhf.so.3`. I'm guessing this is where the `No such file or directory` error comes from! So how do I fix this? – Chris Watts Aug 10 '15 at 22:06
  • Made a symbolic link to point `ld-linux.so.3` to `ld-linux-armhf.so.3` which works as a temporary solution! – Chris Watts Aug 10 '15 at 22:08
  • 2
    You may want to install the "arm-linux-gnueabihf-" toolchain. – Lee Daniel Crocker Aug 10 '15 at 22:37
  • @LeeDanielCrocker That makes it work! Now someone just needs to put all this in a definitive answer – Chris Watts Aug 10 '15 at 23:36
  • can any body answer to this ? http://stackoverflow.com/questions/31916697/cross-arm-gcc-compiling-in-eclipse – tolou.sobh Aug 12 '15 at 10:48
  • http://stackoverflow.com/questions/31916697/cross-arm-gcc-compiling-in-eclipse – tolou.sobh Aug 12 '15 at 10:49

3 Answers3

26

Since nobody from the comments posted the answer, I guess I get the pleasure ;)

No such file or directory comes from when the kernel tries to invoke the dynamic linker specified by the ELF executable's .interp field, but no such file exists.

The .interp field can be found with the following command:

objdump -j .interp -s ./hello_world

In the case of this example, the executable's .interp field was /lib/ld-linux.so.3, but the name of the dynamic linker on the BeagleBone Black is /lib/ld-linux-armhf.so.3.

This happened because the program was compiled with a slightly different toolchain to the one required for the platform. It should be arm-linux-gnueabihf-* rather than arm-linux-gnueabi-*.

The difference between the two is that the Cortex-A8 uses specific floating point registers with the hard-float version (armhf) of the EABI, but the original EABI (armel) uses integer registers for passing around floating point numbers. As a result, armel programs will run on armhf (provided the dynamic linker is set to the correct path!), but not vice versa.

Simply adding a symbolic link ln -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3 is enough to resolve this issue, but the correct fix is to use the right toolchain when compiling the program in the first place.

Chris Watts
  • 6,197
  • 7
  • 49
  • 98
  • Had the same problem on a Zynq CPU, except this time I have no option but to use an armel compiler. I noted that I have to cd into `/lib` before making the links, otherwise it still fails. – Chris Watts Apr 12 '17 at 16:49
  • 3
    There was ARM with hardware floating point long before Cortex-A8. The difference is the original ARM EABI specified that floating point values were passed between functions in integer registers, rather than in hardware floating point registers, to allow the same ABI to be used on hardware without floating point. The compiler would still emit hardware pointing point code. gnueabihf uses floating point registers. – TrentP Apr 29 '18 at 17:25
4

I had the same problem. I downloaded and installed gcc-arm-linuc-gnueabihf package to my Ubuntu PC from the Ubuntu repository using apt-get. Then I compiled a helloworld test program and downloaded it using sftp to my BeagleBone.

Trying to run the program on BBB gave the error: "No such file or directory"

Using objdump I found that the .interp field in the ELF executable was /lib/ld_linux_armhf.so.3. My BBB had dynamic linker /lib/ld-linux.so.3.

I created a symbolic link on the BBB:

ln -s /lib/ld-linux.so.3 /lib-linux-armhf.so.3

Now the cross-compiled application works on BBB. The BBB is running the original Angstrom distribution.

This is not the ideal fix. Now I need to either confgure the toolchain in Ubuntu to add the correct dynamic linker name to the app, or update the BBB to have a dynamic linker specified in the toolchain.

I assume the error message is due to the dynamic linker file not found, not that the application doesn't exist.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
  • So this case is just the opposite issue. There is, however, a compiler flag that should prevent you having to switch compiler. I haven't tried it, but you can add `-mfloat-abi=soft` to your compiler flags to be backwards compatible with `armel`. – Chris Watts Nov 13 '18 at 10:37
0

How to identify the problem?

file cross_compiled_executable

Contains something like:

interpreter /lib/ld-uClibc.so.0

and the problem is that that file does not exist on the target.

How to solve the problem?

Use a proper compiler, either:

  • the person who created the disk image must provide you the cross compiler or tell you exactly how to build it, e.g. with crosstool-ng. For BeagleBone asked at: Toolchain to crosscompile Applications for BBB
  • compile your own image and cross compiler, e.g. with Buildroot. Here is a generic QEMU example. Buildroot has BeagleBone support.
  • use a native compiler on the target. But generally targets are much slower than your host, and space constrained, so you likely don't want to do this.

    You might also be able to use a functional emulator such as QEMU to build, and then only run the programs on a slower platform, e.g. gem5 or a slow board.

Just hacking up the interpreter is potentially not enough, notably you have to ensure binary compatibility between the program and the target libc, or program and kernel interfaces (syscalls, /proc, etc.) if you try to use -static (the target kernel might be too old and not contain the required interfaces). The only robust solution is to use the correct toolchain.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985