使用 gdb 的自定义动态链接器

问题描述 投票:0回答:2

我构建了一个自定义版本的 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
,但最终遇到了同样的错误

c linux gdb glibc
2个回答
0
投票

我使用

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


0
投票

我最近在交叉编译环境中遇到了同样的问题,并且找不到任何解决方案来更改编译后的动态链接器。 这篇文章有点旧,但仍然非常相关,因为我必须花一些时间才能找到解决方案,所以我决定贡献我的方法。我希望这对某些人有帮助。

我的用例有点尴尬,因为我需要运行一个用新的交叉编译器编译的程序,并使用关联的新 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

第一个

PT_INTERP
程序头用于定位ELF解释器的文件名。其他
PT_INTERP
标头将被忽略(自 Linux 2.4.11 起)。

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 :)

注意:如果您在同一主机上执行所有操作,请忽略所有虚拟机和交叉编译详细信息:)

© www.soinside.com 2019 - 2024. All rights reserved.