如何在 gem5 中运行动态链接的可执行系统调用仿真模式 se.py



>之后 在系统调用仿真SE模式下运行gem5时如何解决"致命:内核太旧"?我设法在某些条件下运行了一个静态链接的问候世界。

但是,如果我尝试运行针对 stdlib 的 ARM 动态链接:

./out/common/gem5/build/ARM/gem5.opt ./gem5/gem5/configs/example/se.py -c ./a.out

它失败并显示:

fatal: Unable to open dynamic executable's interpreter.

如何让它找到口译员?希望不要在主机的根目录上复制我的交叉工具链的解释器。

对于x86_64,如果我使用本机编译器,它可以工作,并且正如预期的那样,strace说它正在使用本机解释器,但是如果我使用交叉编译器,则不起作用。

当前的常见问题解答说无法使用动态可执行文件:http://gem5.org/Frequently_Asked_Questions 但我不信任它,然后这些演示文稿提到了它:

  • http://www.gem5.org/wiki/images/0/0c/2015_ws_08_dynamic-linker.pdf
  • http://research.cs.wisc.edu/multifacet/papers/learning_gem5_tutorial.pdf

但不是如何实际使用它。

QEMU 用户模式具有-L选项。

在 gem5 49f96e7b77925837aa5bc84d4c3453ab5f07408e 中测试

https://www.mail-archive.com/gem5-users@gem5.org/msg15582.html

2019 年 11 月添加了对动态链接的支持

在: https://gem5-review.googlesource.com/c/public/gem5/+/23066

当时它肯定在工作,但后来它在某个时候坏了,需要修复......

  • arm 32 位 https://gem5.atlassian.net/browse/GEM5-461
  • 臂 64 位 https://gem5.atlassian.net/browse/GEM5-828

如果你有一个根文件系统可以使用,例如一个由 Buildroot 生成的文件系统,你可以这样做:

./build/ARM/gem5.opt configs/example/se.py 
--redirects /lib=/path/to/build/target/lib 
--redirects /lib64=/path/to/build/target/lib64 
--redirects /usr/lib=/path/to/build/target/usr/lib 
--redirects /usr/lib64=/path/to/build/target/usr/lib64 
--interp-dir /path/to/build/target 
--cmd /path/to/build/target/bin/hello

或者,如果您使用的是 Ubuntu 交叉编译器工具链,例如在 Ubuntu 18.04 中:

sudo apt install gcc-aarch64-linux-gnu
aarch64-linux-gnu-gcc -o hello.out hello.c
./build/ARM/gem5.opt configs/example/se.py 
--interp-dir /usr/aarch64-linux-gnu 
--redirects /lib=/usr/aarch64-linux-gnu/lib 
--cmd hello.out

还必须将可能包含动态库的任何路径添加为单独的--redirect。这些对于 C 可执行文件来说已经足够了。

--interp-dir根据 ELF 元数据设置将搜索动态加载程序的根目录,该元数据表示加载程序的路径。例如,buildroot ELF 文件将该路径设置为/lib/ld-linux-aarch64.so.1,而加载程序是存在于/path/to/build/target/lib/ld-linux-aarch64.so.1的文件。正如布兰登所提到的,这条路径可以通过以下方式找到:

readelf -a $bin_name | grep interp

syscall 仿真动态链接的主要困难在于,我们希望以某种方式:

  • 链接器文件访问以转到魔术目录以查找那里的库
  • 从主应用程序访问其他文件以转到正常路径,例如读取当前工作目录中的输入文件

而且很难检测到我们是否在加载器中,特别是因为这可以通过程序中间的dlopen发生。

--redirects选项是一个简单的解决方案。

例如,/lib=/path/to/build/target/lib使得如果来宾访问 C 标准库/lib/libc.so.6,则 gem5 会看到这在/lib内部,并将路径重定向到/path/to/build/target/lib/libc.so.6

轻微的缺点是无法实际访问主机/lib目录中的文件,但这并不常见,因此在大多数情况下都可以工作。

如果您错过了任何--redirect,动态链接器可能会抱怨找不到库,并显示以下消息:

hello.out: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory

如果发生这种情况,您必须在目标文件系统/工具链中找到libstdc++.so.6库并添加缺少的--redirect

它后来在 https://gem5.atlassian.net/browse/GEM5-430 时坏了,但又被修复了。

动态链接的缺点

一旦我有了动态链接的工作,我注意到它实际上有以下缺点,根据应用程序的不同,这些缺点可能会也可能不会很大:

  • 动态链接器必须运行一些指令,如果你有一个非常小的用户空间测试可执行文件,并且在像O3这样的低CPU上运行,那么这个启动可以主导运行时,所以要注意这一点

  • ExecAll不显示 stdlib 函数的符号名称,您只是从一些随机最近的符号中获得偏移量,例如@__end__+274873692728.也许沿着这些思路可以工作:使用 gdbserver 调试共享库但不确定

  • 第一次动态跳转到 stdlib 功能需要通过动态链接机制,如果您尝试控制微型工作台,这可能会产生问题。

    实际上,我已经遇到过一次了:程序的动态版本正在做一些额外的事情,再加上gem5错误,破坏了我的实验,并花费了我几个小时的调试时间。

Python和Java这样的解释器

Python和Java只是可执行文件,并且是执行可执行文件参数的脚本。

因此,从理论上讲,您可以在系统调用仿真模式下运行它们,例如:

build/ARM/gem5.opt configs/example/se.py --cmd/usr/bin/python --options='hello.py arg1 arg2'

然而,在实践中,考虑到截至2019 年 11 月的 gem5 当前状态,像解释器这样非常复杂的可执行文件可能会有尚未实现的系统调用,另请参阅:何时在 gem5 中的用户空间程序中使用完整系统 FS 与系统调用仿真 SE?

一般来说,实现/忽略不需要的调用并不难,所以试一试。相关主题:

Java
  • :在gem5(或任何非C语言)中运行Java程序
  • Python:3.6.8 aarch64 失败,并显示"致命:系统调用未使用#278 (#278) 未实现"。

旧答案

我被告知,截至 49f96e7b77925837aa5bc84d4c3453ab5f07408e(2018 年 5 月),没有方便/经过良好测试的方法在 syscall 仿真中运行动态链接的交叉架构可执行文件:https://www.mail-archive.com/gem5-users@gem5.org/msg15585.html

但是,我怀疑修补 gem5 以支持它并不难。QEMU 用户模式已经支持这一点,您只需要使用-L指向根文件系统。

交叉编译的二进制文件如果是动态可执行文件,则应具有 .interp 条目。

用 readelf 验证它:

readelf -a $bin_name | grep interp

模拟器设置为在将可执行文件加载到模拟地址空间时在主可执行文件中查找此部分。如果此部分存在,则 c 字符串设置为指向该文本(通常类似于/lib64/ld-linux-x86-64.so.2)。然后,模拟器调用 glibc 的 open 函数,并将该 c 字符串作为参数。实际上,这会将模拟器的动态链接器加载程序作为普通文件打开。然后,模拟器使用 mmap 和 mmap_fixed分阶段将文件映射到模拟地址空间。

对于交叉编译,此代码必须失败。如果模拟器无法打开文件,则错误消息会直接跟随它。若要完成此操作,需要调试打开过程,并可能调试随后将加载程序粘贴到地址空间中。有一种机制可以将程序的入口点设置到加载器中,而不是直接设置到主二进制文件的代码部分。(这是通过堆栈上的辅助向量完成的。您可能还需要尝试一下。

有趣的代码是(截至05/29/19)在src/base/loader/elf_object.cc.

我在交叉编译代码后遇到了这个问题。您可以尝试在命令后添加"--static"。

最新更新