尝试在目标设备上运行交叉编译的可执行文件时出现错误:没有这个文件或目录。

17

我陷入了交叉编译的世界,这并不是那么阳光。

我正在尝试为我的BeagleBone Black(运行TI Cortex-A8处理器)编译一个简单的hello world应用程序。

首先,我使用gcc在x86上成功编译并运行了hello world应用程序。

然后我将我的编译设置更改为以下内容:

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

我使用SCP将文件传输到BeagleBone,并使用chmod +x hello_world设置了可执行权限。

在运行./hello_world后,唯一的回应是:

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

file 命令的输出结果与 /sbin/init 命令的结果相同,正如我所期望的:

$ 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

ldd的结果是:

$ ldd hello_world
    not a dynamic executable

我尝试添加了适当的平台和CPU类型,并将我的编译更改为:

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

起初,我的操作出错了,显示文本文件繁忙,但之后我再也没有遇到这个错误了,现在变成了没有这个文件或目录。我猜那次的错误可能只是一个错误的转移或其他什么问题。


1
你是否试图从noexec分区运行hello_world? - adelphus
你尝试过静态链接吗?我怀疑你的BB上没有所需的库。 - Eugene Sh.
@adelphus 我把 /bin/hostname 复制到我正在运行的目录中,它可以正确地执行。 - Chris Watts
1
一个常见的导致这些结果/错误的情况是,当您使用与目标不同的运行时进行编译/链接时,可执行文件引用了目标上不存在的动态链接器。例如,您已将可执行文件链接到glibc,而目标使用uClibc。如果您在strace下运行程序,则可以获得更多线索。要找出可执行文件使用的动态链接器,请运行“objdump -j .interp -s ./filename”。 - nos
2
您可能需要安装“arm-linux-gnueabihf-”工具链。 - Lee Daniel Crocker
显示剩余11条评论
3个回答

26

由于没有人在评论中发布答案,我想我可以有这个荣幸 ;)

No such file or directory 出现的原因是内核尝试调用由ELF可执行文件的 .interp字段指定的动态链接器,但是找不到该文件。

可以使用以下命令查找 .interp 字段:

objdump -j .interp -s ./hello_world
在这个例子中,可执行文件的.interp字段是/lib/ld-linux.so.3,但BeagleBone Black上动态链接器的名称是/lib/ld-linux-armhf.so.3
这是因为该程序使用了与所需平台略有不同的工具链进行编译。正确的工具链应该是arm-linux-gnueabihf-*而不是arm-linux-gnueabi-*
两者之间的区别在于Cortex-A8使用具有硬件浮点版本(armhf)的EABI的特定浮点寄存器,但原始EABI(armel)使用整数寄存器来传递浮点数。因此,armel程序将在armhf上运行(前提是动态链接器设置为正确的路径!),但反之则不行。
简单地添加符号链接ln -s /lib/ld-linux-armhf.so.3 /lib/ld-linux.so.3就足以解决此问题,但正确的修复方法是在首次编译程序时使用正确的工具链。

在Zynq CPU上遇到了同样的问题,但这次我别无选择,只能使用armel编译器。我注意到在创建链接之前必须先进入/lib目录,否则仍然会失败。 - Chris Watts
3
早在Cortex-A8出现之前,ARM就已经有了硬件浮点运算功能。不同之处在于,最初的ARM EABI规范指定,浮点值是通过整数寄存器而不是硬件浮点寄存器在函数之间传递的,以便在没有浮点功能的硬件上使用相同的ABI。编译器仍会生成硬件浮点代码。gnueabihf使用浮点寄存器。 - TrentP

4
我有同样的问题。我从Ubuntu仓库使用apt-get下载并安装了gcc-arm-linuc-gnueabihf软件包到我的Ubuntu电脑上。然后我编译了一个helloworld测试程序,并使用sftp将其下载到我的BeagleBone。
在BBB上尝试运行该程序时出现错误:“没有这样的文件或目录”。
使用objdump,我发现ELF可执行文件中的.interp字段是/lib/ld_linux_armhf.so.3。我的BBB上有动态链接器/lib/ld-linux.so.3
我在BBB上创建了一个符号链接:
ln -s /lib/ld-linux.so.3 /lib-linux-armhf.so.3

现在交叉编译的应用程序可以在BBB上运行。BBB正在运行原始的Angstrom发行版。
这不是理想的解决方法。现在我需要在Ubuntu中配置工具链,添加正确的动态链接器名称到应用程序中,或者更新BBB,指定一个在工具链中指定的动态链接器。
我认为错误消息是由于找不到动态链接器文件而不是应用程序不存在。

所以这个情况只是相反的问题。然而,有一个编译器标志应该可以防止你不得不更换编译器。我没有尝试过,但是你可以在编译器标志中添加“-mfloat-abi=soft”,以与“armel”向后兼容。 - Chris Watts

0

如何识别问题?

file cross_compiled_executable

包含类似以下内容:

interpreter /lib/ld-uClibc.so.0

问题在于目标位置上不存在该文件。

如何解决这个问题?

使用适当的编译器,包括:

  • 创建磁盘映像的人必须为您提供交叉编译器或者准确告诉您如何构建它,例如使用crosstool-ng。对于BeagleBone,请参考:Toolchain to crosscompile Applications for BBB
  • 自己编译镜像和交叉编译器,例如使用Buildroot。这里有一个通用的QEMU示例。Buildroot 支持BeagleBone
  • 在目标设备上使用本地编译器。但是一般来说,目标设备比主机慢得多,并且空间受限,所以您可能不想这样做。

    您还可以尝试使用功能强大的模拟器(例如QEMU)进行构建,然后只在较慢的平台上运行程序,例如gem5或慢速板子。

仅仅对解释器进行黑客攻击可能是不够的,特别是你必须确保程序与目标libc之间的二进制兼容性,或者程序与内核接口(系统调用,/proc等)之间的兼容性,如果你尝试使用-static(目标内核可能太旧,不包含所需的接口)。唯一稳健的解决方案是使用正确的工具链。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接