【问题标题】:How to solve "error while loading shared libraries" when trying to run an arm binary with qemu-arm?尝试使用 qemu-arm 运行 arm 二进制文件时如何解决“加载共享库时出错”?
【发布时间】:2013-04-16 01:21:17
【问题描述】:

我正在运行安装了 qemu、qemu-user 和 gnueabi 工具链的 Linux Mint 14。我用arm-linux-gnueabi-gcc test.c -o test编译了test.c。

当我尝试运行qemu-arm /usr/arm-linux-gnueabi/lib/ld-linux.so.3 test

我收到一条错误消息:test: error while loading shared libraries: test: cannot open shared object file: No such file or directory。正如我之前尝试过的那样,运行qemu-arm test 会得到/lib/ld-linux.so.3: No such file or directory

但是,该文件确实存在并且可以访问。

$ stat /usr/arm-linux-gnueabi/lib/ld-linux.so.3
  File: `/usr/arm-linux-gnueabi/lib/ld-linux.so.3' -> `ld-2.15.so'
  Size: 10          Blocks: 0          IO Block: 4096   symbolic link
Device: 801h/2049d  Inode: 4083308     Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2013-04-22 16:19:48.090613901 -0700
Modify: 2012-09-21 08:31:29.000000000 -0700
Change: 2013-04-22 15:58:41.042542851 -0700
 Birth: -

有谁知道如何让 qemu 运行一个 arm 程序而不必模拟整个 arm Linux 内核?

test.c 是

#include <stdio.h>
int main() {
    printf("this had better work\n");
}

file test

test: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.31, BuildID[sha1]=0xf2e49db65394b77c77ee5b65b83c0cc9220cbfc0, not stripped

【问题讨论】:

  • 如果在没有操作系统的情况下运行, printf 是您最不想做的事情,当然不是您想为该系统编写的第一个程序。打开一个在 qemu 上没有意义的 LED,但是将一个字符从串行端口/uart 干扰到串行终端通常是微不足道的。此外,您可能希望从汇编程序而不是 C 开始,因为引导代码也不是微不足道的,因为您必须确保了解内存映射、程序加载位置等。
  • 这来自未作为系统库安装的 arm 库(即使它们作为交叉编译器的目标库安装)。如果发行版支持它,那么您可以将 arm 安装为多架构目标(例如如何同时支持 x86 和 x86_64)。在 Ubuntu 中,这类似于 apt-add-architecture arm &amp;&amp; apt-get install libc6:arm。我不知道薄荷。如果您不想考虑,只需使用 -static 编译即可。

标签: arm qemu


【解决方案1】:

如果你想在没有 Linux 的情况下运行 ARM,那么你需要一个不同的编译器(至少)。 arm-linux-gnueabi-gccLinux 的编译器。编译器和libc 密切相关。您将需要一个带有 qemu 可移植层的 newlib 编译器。porting newlib

请参阅:BalauGoogle newlib+qemunewlib 端口托管在 Github 上,似乎与 Balau 博客相同。

非 Linux gcc 通常称为arm-none-eabi-gcc。前缀 arm-none-eabi- 被一些配置脚本识别。

【讨论】:

  • 如果你想进行系统调用,这很重要,对于不需要系统调用的裸机工作,你可以在大多数情况下使用 arm-linux-gnueabi 或 arm-none-eabi 风格的工具链。
  • github.com/dwelch67/yagbat 有一个 qemu 目录,我正在开发一个单独的 qemu 裸机示例 repo,但还没有任何东西要发布。
  • @dwelch 对,你也可以用-nostdlib 编译,但是你必须编写你自己的库和libgcc 的东西。例如,当您除以零时,libgccLinux 版本所做的事情与newlib 不同(我认为它会重置)。我认为这张海报最好使用 newlib gcc,但你是对的,如果你小心的话,你可以使用arm-linux-gnueabi-gcc 编译器。这条路线很可能会出现很多随机的链接器/加载器错误,这些错误通常不容易弄清楚。
  • 答案的关键是“qemu 的可移植层”,这很重要。如果您进行系统调用,任何旧的 arm-none-eabi 都将无法工作。但是,如果您不进行系统调用,那么任何 arm-linux-gnueabi 或 arm-none-eabi 都将作为编译器工作,并强调您使用 -nostdlib 等……如果您可以构建自己的或找到一个 newlib那么平台肯定会使用 arm-none-eabi。
【解决方案2】:

我通过将以下库复制到 /lib 中解决了这个问题,但我相信应该有更好的解决方案,而不是我发明的这个讨厌的解决方案!

sudo cp  /usr/arm-linux-gnueabi/lib/ld-linux.so.3 /lib
sudo cp /usr/arm-linux-gnueabi/lib/libgcc_s.so.1 /lib
sudo cp /usr/arm-linux-gnueabi/lib/libc.so.6 /lib

如果我有兴趣了解其他更好的解决方案,请告诉我。

【讨论】:

  • 是的,这当然可以,但在这种情况下您需要运行 Linux。最初的问题是避免 Linux。您没有复制库并在没有 Linux 内核的情况下运行 qemu 虚拟机?这似乎是不可能的。
  • 我发现 qemu-arm 的 -L /usr/arm-linux-gnueabihf/ 选项可以工作,正如上面所建议的......
  • @artlessnoise,这里没有错。这个答案使库对 qemu 可见,因此模拟的二进制文件将链接。它不是在引导模拟的 Linux 系统。它仍在使用系统调用仿真。
  • @artlessnoise,这就是 qemu does]。首先,它必须能够将 ARM 二进制文件与 ARM 库链接(除非它是静态的),然后这些库进行系统调用,qemu 捕获这些系统调用,然后转换到主机操作系统。这比必须模拟整个 ARM Linux 内核要高效得多。这个解决方案只是将库移动到 qemu 可以找到它们的地方。这些库仍然必须进行系统调用才能发生任何有趣的事情。
  • @sh1 对,但是 ARM 系统调用接口与 x86 不同。有些事情不存在于一个上,而存在于另一个上。 qemu 必须做这个翻译或者在某些情况下实现它;这可能是不可能的,因为它需要直接访问 Linux 内部。使用 arm-none 编译器似乎不太麻烦。同样,这取决于您要达到的目标。我并没有说这在所有情况下都不起作用。但是,它与其他解决方案有所取舍。
【解决方案3】:

您可以通过使用 -L 标志提供 arm-linux-gnueabi 共享库的路径来运行示例。

qemu-arm -L /usr/arm-linux-gnueabi/

还要确保未设置 LD_LIBRARY_PATH。

unset LD_LIBRARY_PATH

【讨论】:

  • -L /usr/arm-linux-gnueabihf 用于 Ubuntu 16.04 软件包 gcc-arm-linux-gnueabihf
  • qemu-aarch64 -L /usr/aarch64-linux-gnu/ for ARMv8 64
【解决方案4】:

我在使用汇编代码运行 C 程序时也遇到了这个问题。我的解决方案是使用“-static”选项构建可执行文件,例如

arm-linux-gnueabi-gcc -static -g main.c square.s

然后

qemu-arm a.out

不会报“找不到/lib/ld-linux.so.3”的错误。

唯一的缺点是可执行文件可能很大。但是,当您只想测试代码时,它会很有帮助。

当然,您可以使用 Balau 的方法(请参阅 artless noise 的答案)。但是如果你不想在这一步中因为“UART串口”之类的东西而感到沮丧,这只是为了运行一个简单的“测试”功能,那就试试我的修复吧。

【讨论】:

  • 老兄!现在是 2018 年,您的解决方案对我有用。想详细说明-static 是如何发挥魅力的吗?
  • @J.Doe 偶然发现了这一点,所以我想我应该详细说明一下。我已经使用-static 标志编译了一段时间了。它之所以有效,是因为使用此标志进行交叉编译时,所有依赖项都被编译到可执行文件本身中,而不是留给链接器解析。当您在另一台机器上运行生成的可执行文件时(在本例中为qemu-arm),没有未解决的依赖关系,因此它就像一个魅力
  • @agdhruv,现在是 2019 年,我在很长一段时间后重新登录了这个帐户。您的答案只有 3 天。 =))
【解决方案5】:
$ export QEMU_LD_PREFIX=/usr/arm-linux-gnueabi

这对我有用。 基本上是一样的:

$ qemu-arm -L /usr/arm-linux-gnueabi/

您可以将其添加到 ~/.bashrc 文件中,这样您就不必每次打开终端时都输入它。

【讨论】:

    【解决方案6】:

    对我有用的一个变体是直接传递加载程序库并使用加载程序参数--library-path 指定所需的库路径。例如:

    $ TOOLCHAIN_ROOT=/usr/local/gcc-linaro-arm-linux-gnueabihf-4.7-2013.03-20130313_linux/arm-linux-gnueabihf
    $ qemu-arm $TOOLCHAIN_ROOT/libc/lib/ld-linux-armhf.so.3 --library-path $TOOLCHAIN_ROOT/libc/lib/arm-linux-gnueabihf:/$TOOLCHAIN_ROOT/lib ./my_executable
    

    或者等效地导出LD_LIBRARY_PATH,而不是使用--library-path

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-17
      • 2022-07-16
      • 2019-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-19
      • 1970-01-01
      相关资源
      最近更新 更多