我构建了一个自定义版本的 glibc。它引入了一些我与自定义共享库一起使用的新符号。为此,我添加了一个新版本:
SHIM
我使用
gcc -g -o my_test my_test.c -l my_so.so -Wl,-dynamic-linker=/local/home/me/glibc-build/ld-linux-x86-64.so.2
构建测试可执行文件。它需要使用我的自定义 glibc 构建的运行时链接器,以便它可以链接 my_so.so 中使用的自定义 glibc 符号。这确实有效。
但是当我使用
gdb
调试可执行文件时,我发现使用了默认的运行时链接器。我收到以下错误:
/bin/bash:/lib64/ld-linux-x86-64.so.2:找不到版本“SHIM”(/local/home/me/glibc-build/libc.so.6需要)
如何让 gdb 使用我的自定义运行时链接器?我尝试使用
gdb --args /local/home/me/glibc-build/ld-linux-x86-64.so.2 ./my_test
,但最终遇到了同样的错误
我使用
构建测试可执行文件。gcc -g -o my_test my_test.c -l my_so.so -Wl,-dynamic-linker=/local/home/me/glibc-build/ld-linux-x86-64.so.2
使用上述命令链接可执行文件是不完整。我猜您还必须设置
LD_LIBRARY_PATH=/local/home/me/glibc-build:/local/home/me/glibc-build/elf:...
才能使 my_test
工作,而 LD_LIBRARY_PATH
的设置会阻止 /bin/bash
工作。
您可以通过运行(在当前环境中)来确认这一点:
bash -c ./my_test
这正是 GDB 正在做的事情,并且应该会因相同的错误而失败。
如果我的猜测是正确的,解决此问题的最佳方法是取消设置
LD_LIBRARY_PATH
并使用 -Wl,-rpath=/local/home/me/glibc-build:/local/home/me/glibc-build/elf:...
重新链接可执行文件,这样 my_test
根本不需要设置 LD_LIBRARY_PATH
。
我最近在交叉编译环境中遇到了同样的问题,并且找不到任何解决方案来更改编译后的动态链接器。 这篇文章有点旧,但仍然非常相关,因为我必须花一些时间才能找到解决方案,所以我决定贡献我的方法。我希望这对某些人有帮助。
我的用例有点尴尬,因为我需要运行一个用新的交叉编译器编译的程序,并使用关联的新 libgcc.so 和自定义 glibc 版本(因此需要新的动态链接器)。
简短回答:
我将此链接器选项
-Wl,-dynamic-linker,custom_path_to_dynamic_linker
传递给了 GCC。
详情:
https://sourceware.org/binutils/docs-2.42/ld/Options.html
--dynamic-linker=file
设置动态链接器的名称。这仅在生成动态链接的 ELF 可执行文件时才有意义。默认的动态链接器通常是正确的;除非您知道自己在做什么,否则不要使用此功能。
根据我的经验,动态链接器在编译后不能轻易更改,除非您手动编辑ELF程序头。 您可以将其内容可视化如下:
$ aarch64-none-linux-gnu-readelf -e ./a.out
...
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R 0x8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x0000000000000070 0x0000000000000070 R 0x1
[Requesting program interpreter: ${target_runtime_sys_root}/libc/lib/ld-linux-aarch64.so.1]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000001e8b4 0x000000000001e8b4 R E 0x10000
LOAD 0x000000000001fd30 0x000000000042fd30 0x000000000042fd30
0x0000000000000458 0x0000000000000470 RW 0x10000
DYNAMIC 0x000000000001fd90 0x000000000042fd90 0x000000000042fd90
0x0000000000000220 0x0000000000000220 RW 0x8
NOTE 0x00000000000002a8 0x00000000004002a8 0x00000000004002a8
0x0000000000000020 0x0000000000000020 R 0x4
GNU_EH_FRAME 0x000000000001c58c 0x000000000041c58c 0x000000000041c58c
0x0000000000000734 0x0000000000000734 R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x000000000001fd30 0x000000000042fd30 0x000000000042fd30
0x00000000000002d0 0x00000000000002d0 R 0x1
...
https://docs.kernel.org/userspace-api/ELF.html
PT_INTERP
第一个
程序头用于定位ELF解释器的文件名。其他PT_INTERP
标头将被忽略(自 Linux 2.4.11 起)。PT_INTERP
PT_INTERP
的值通常指向与您的平台对应的ld.so.1
。
您可以通过将此链接器选项
-Wl,-dynamic-linker,custom_path_to_dynamic_linker
传递给 GCC 来更改其值。
构建:
aarch64-none-linux-gnu-g++ -march=armv9.4-a -O0 -g3 -std=c++23 \
-o ./a.out \
test.cpp \
-Wl,-L${cross_gcc_sys_root}/lib/gcc/aarch64-none-linux-gnu/15.0.0 \
-Wl,-lbacktrace \
-Wl,-dynamic-linker,${target_runtime_sys_root}/libc/lib/ld-linux-aarch64.so.1
在虚拟机中,从发行版的存储库安装了最新的 GDB:
$ gdb ./a.out
# Set the environment variables
(gdb) python gdb.execute("set environment LD_LIBRARY_PATH=${target_runtime_sys_root}/lib64:${target_runtime_sys_root}/libc/lib64")
# Run the program
(gdb) run [arg1 arg2 ...]
# That's all! It should work now :)
注意:如果您在同一主机上执行所有操作,请忽略所有虚拟机和交叉编译详细信息:)