LD_DEBUG环境变量 (2012)
摘要
解释如何在Linux上使用LD_DEBUG环境变量来调试共享库加载问题,包含示例和相关工具。
暂无内容
查看缓存全文
缓存时间: 2026/06/10 00:22
# LD_DEBUG 环境变量
来源:https://bnikolic.co.uk/blog/linux-ld-debug.html
*2012年4月23日首次发布,2019年9月10日更新(添加问题排查工具链接),2019年10月18日更新(迁移至 Jekyll),2023年4月3日更新(添加其他工具链接)*
开发使用大量共享(动态)加载库的大型系统时,有时会遇到一些令人沮丧且难以诊断的错误。这些错误通常源于系统上存在多个不同版本的库,而加载的是“错误”版本,而非开发者想要的版本。
> ***注意***您可能还会发现我的在线工具(用于诊断 Linux 链接器问题)很有用:http://linkdemo.carabinerweb.s3-website-us-east-1.amazonaws.com/ 它以专家系统实现。撰写此文时正在扩展,但可能已经有用。
过去,我经常使用 `strace` 命令(man strace (http://linux.die.net/man/1/strace))来有效调试这些问题,通过检查哪些库被访问。然而,有一种更高效但可能不太为人所知的调试共享库加载问题的方法:`LD_DEBUG` 环境变量。
如果设置了 `LD_DEBUG` 变量,Linux 动态链接器将输出调试信息,这些信息可以非常快速地解决大多数加载问题。要查看可用选项,只需用 `help` 值运行任何程序,例如:
``
LD_DEBUG=help cat
Valid options for the LD_DEBUG environment variable are:
libs display library search paths
reloc display relocation processing
files display progress for input file
symbols display symbol table processing
bindings display information about symbol binding
versions display version dependencies
all all previous options combined
statistics display relocation statistics
unused determined unused DSOs
help display this help message and exit
To direct the debugging output into a file instead of standard output
a filename can be specified using the LD_DEBUG_OUTPUT environment
variable.
``
> ***注意***还有许多其它有用的工具可以处理链接问题:1. `strace` (https://linux.die.net/man/1/strace) 程序提供所有系统调用的洞察,包括搜索、打开动态库 2. `ldd` (https://linux.die.net/man/1/ldd) 程序解析动态库依赖 3. `objdump -x YOURFILE | grep NEEDED` 命令列出程序或库中需要哪些其它库的记录 4. `patchelf` (https://github.com/NixOS/patchelf) 程序可以轻松更改 ELF 可执行文件的 `rpath`,从而改变内建搜索顺序 5. `LD_PRELOAD` (https://bnikolic.co.uk/blog/hpc-ldpreload-speedoptimisation) 环境变量可以轻松替换动态库。需要进一步帮助?凭借 20 多年的经验,我们独具优势——请联系我们:[email protected]
> ***注意***此变量仅 Linux 可用。在 MS Windows 上,可以通过启用 *“Show Loader Snaps”* (https://abitofscotland.wordpress.com/2019/12/20/dll-load-failure/) 来获取类似信息,使用 `gflags.exe` 程序启用该功能,然后使用 `windbg` 查看日志。例如:1. 安装包含 `gflags` 和 `windbg` 的 Windows SDK:`winget install Microsoft.WindowsSDK.10.0.19041` (或从 Microsoft 网站下载 (https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-download-tools)) 2. 为可执行文件启用 ShowLoaderSnaps。例如,在 Powershell 中为 `notepad.exe` 启用:`&"C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\gflags.exe" /i notepad.exe +sls` 3. 在 WinDbg 应用下执行 `notepad.exe`。将显示详细的 DLL 加载日志
以下是我笔记本电脑上的运行示例:
``
LD_DEBUG=all cat
28504:
28504: file=libc.so.6 [0]; needed by cat [0]
28504: find library=libc.so.6 [0]; searching
28504: search path=/home/bnikolic/s/lib/tls/x86_64:/home/bnikolic/s/lib/tls:/home/bnikolic/s/lib/x86_64:/home/bnikolic/s/lib:tls/x86_64:tls:x86_64::/home/bnikolic/d/p/R-2.14.1bin/lib/R/lib/tls/x86_64:/home/bnikolic/d/p/R-2.14.1bin/lib/R/lib/tls:/home/bnikolic/d/p/R-2.14.1bin/lib/R/lib/x86_64:/home/bnikolic/d/p/R-2.14.1bin/lib/R/lib (LD_LIBRARY_PATH)
28504: trying file=/home/bnikolic/s/lib/tls/x86_64/libc.so.6
28504: trying file=/home/bnikolic/s/lib/tls/libc.so.6
28504: trying file=/home/bnikolic/s/lib/x86_64/libc.so.6
28504: trying file=/home/bnikolic/s/lib/libc.so.6
28504: trying file=tls/x86_64/libc.so.6
28504: trying file=tls/libc.so.6
28504: trying file=x86_64/libc.so.6
28504: trying file=libc.so.6
28504: trying file=/home/bnikolic/d/p/R-2.14.1bin/lib/R/lib/tls/x86_64/libc.so.6
28504: trying file=/home/bnikolic/d/p/R-2.14.1bin/lib/R/lib/tls/libc.so.6
28504: trying file=/home/bnikolic/d/p/R-2.14.1bin/lib/R/lib/x86_64/libc.so.6
28504: trying file=/home/bnikolic/d/p/R-2.14.1bin/lib/R/lib/libc.so.6
28504: search cache=/etc/ld.so.cache
28504: trying file=/lib/x86_64-linux-gnu/libc.so.6
28504:
28504: file=libc.so.6 [0]; generating link map
28504: dynamic: 0x00007fc38e525b40 base: 0x00007fc38e18c000 size: 0x00000000003a0368
28504: entry: 0x00007fc38e1ad420 phdr: 0x00007fc38e18c040 phnum: 10
28504:
28504: checking for version `GLIBC_2.4' in file /lib/x86_64-linux-gnu/libc.so.6 [0] required by file cat [0]
28504: checking for version `GLIBC_2.3' in file /lib/x86_64-linux-gnu/libc.so.6 [0] required by file cat [0]
28504: checking for version `GLIBC_2.3.4' in file /lib/x86_64-linux-gnu/libc.so.6 [0] required by file cat [0]
28504: checking for version `GLIBC_2.2.5' in file /lib/x86_64-linux-gnu/libc.so.6 [0] required by file cat [0]
28504: checking for version `GLIBC_2.3' in file /lib64/ld-linux-x86-64.so.2 [0] required by file /lib/x86_64-linux-gnu/libc.so.6 [0]
28504: checking for version `GLIBC_PRIVATE' in file /lib64/ld-linux-x86-64.so.2 [0] required by file /lib/x86_64-linux-gnu/libc.so.6 [0]
28504:
28504: relocation processing: /lib/x86_64-linux-gnu/libc.so.6 (lazy)
28504: symbol=_res; lookup in file=cat [0]
28504: symbol=_res; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `_res' [GLIBC_2.2.5]
28504: symbol=_IO_file_close; lookup in file=cat [0]
28504: symbol=_IO_file_close; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `_IO_file_close' [GLIBC_2.2.5]
28504: symbol=stderr; lookup in file=cat [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to cat [0]: normal symbol `stderr' [GLIBC_2.2.5]
28504: symbol=error_one_per_line; lookup in file=cat [0]
28504: symbol=error_one_per_line; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `error_one_per_line' [GLIBC_2.2.5]
28504: symbol=__malloc_initialize_hook; lookup in file=cat [0]
28504: symbol=__malloc_initialize_hook; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__malloc_initialize_hook' [GLIBC_2.2.5]
28504: symbol=__morecore; lookup in file=cat [0]
28504: symbol=__morecore; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__morecore' [GLIBC_2.2.5]
28504: symbol=__key_encryptsession_pk_LOCAL; lookup in file=cat [0]
28504: symbol=__key_encryptsession_pk_LOCAL; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__key_encryptsession_pk_LOCAL' [GLIBC_2.2.5]
28504: symbol=__progname_full; lookup in file=cat [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to cat [0]: normal symbol `__progname_full' [GLIBC_2.2.5]
28504: symbol=__ctype32_tolower; lookup in file=cat [0]
28504: symbol=__ctype32_tolower; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__ctype32_tolower' [GLIBC_2.2.5]
28504: symbol=__key_gendes_LOCAL; lookup in file=cat [0]
28504: symbol=__key_gendes_LOCAL; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__key_gendes_LOCAL' [GLIBC_2.2.5]
28504: symbol=_environ; lookup in file=cat [0]
28504: symbol=_environ; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `_environ' [GLIBC_2.2.5]
28504: symbol=_rtld_global; lookup in file=cat [0]
28504: symbol=_rtld_global; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: symbol=_rtld_global; lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib64/ld-linux-x86-64.so.2 [0]: normal symbol `_rtld_global' [GLIBC_PRIVATE]
28504: symbol=__progname; lookup in file=cat [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to cat [0]: normal symbol `__progname' [GLIBC_2.2.5]
28504: symbol=argp_err_exit_status; lookup in file=cat [0]
28504: symbol=argp_err_exit_status; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `argp_err_exit_status' [GLIBC_2.2.5]
28504: symbol=mallwatch; lookup in file=cat [0]
28504: symbol=mallwatch; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `mallwatch' [GLIBC_2.2.5]
28504: symbol=__rcmd_errstr; lookup in file=cat [0]
28504: symbol=__rcmd_errstr; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__rcmd_errstr' [GLIBC_2.2.5]
28504: symbol=svcauthdes_stats; lookup in file=cat [0]
28504: symbol=svcauthdes_stats; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `svcauthdes_stats' [GLIBC_2.2.5]
28504: symbol=__libc_enable_secure; lookup in file=cat [0]
28504: symbol=__libc_enable_secure; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: symbol=__libc_enable_secure; lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib64/ld-linux-x86-64.so.2 [0]: normal symbol `__libc_enable_secure' [GLIBC_PRIVATE]
28504: symbol=_res_hconf; lookup in file=cat [0]
28504: symbol=_res_hconf; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `_res_hconf' [GLIBC_2.2.5]
28504: symbol=malloc; lookup in file=cat [0]
28504: symbol=malloc; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `malloc' [GLIBC_2.2.5]
28504: symbol=getdate_err; lookup in file=cat [0]
28504: symbol=getdate_err; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `getdate_err' [GLIBC_2.2.5]
28504: symbol=__tzname; lookup in file=cat [0]
28504: symbol=__tzname; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__tzname' [GLIBC_2.2.5]
28504: symbol=__timezone; lookup in file=cat [0]
28504: symbol=__timezone; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__timezone' [GLIBC_2.2.5]
28504: symbol=_rtld_global_ro; lookup in file=cat [0]
28504: symbol=_rtld_global_ro; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: symbol=_rtld_global_ro; lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib64/ld-linux-x86-64.so.2 [0]: normal symbol `_rtld_global_ro' [GLIBC_PRIVATE]
28504: symbol=optarg; lookup in file=cat [0]
28504: symbol=optarg; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `optarg' [GLIBC_2.2.5]
28504: symbol=__ctype_tolower; lookup in file=cat [0]
28504: symbol=__ctype_tolower; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__ctype_tolower' [GLIBC_2.2.5]
28504: symbol=__ctype_toupper; lookup in file=cat [0]
28504: symbol=__ctype_toupper; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__ctype_toupper' [GLIBC_2.2.5]
28504: symbol=svc_max_pollfd; lookup in file=cat [0]
28504: symbol=svc_max_pollfd; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `svc_max_pollfd' [GLIBC_2.2.5]
28504: symbol=__ctype_b; lookup in file=cat [0]
28504: symbol=__ctype_b; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__ctype_b' [GLIBC_2.2.5]
28504: symbol=argp_program_version_hook; lookup in file=cat [0]
28504: symbol=argp_program_version_hook; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `argp_program_version_hook' [GLIBC_2.2.5]
28504: symbol=__after_morecore_hook; lookup in file=cat [0]
28504: symbol=__after_morecore_hook; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__after_morecore_hook' [GLIBC_2.2.5]
28504: symbol=__environ; lookup in file=cat [0]
28504: symbol=__environ; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__environ' [GLIBC_2.2.5]
28504: symbol=__ctype32_b; lookup in file=cat [0]
28504: symbol=__ctype32_b; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__ctype32_b' [GLIBC_2.2.5]
28504: symbol=__curbrk; lookup in file=cat [0]
28504: symbol=__curbrk; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__curbrk' [GLIBC_2.2.5]
28504: symbol=argp_program_version; lookup in file=cat [0]
28504: symbol=argp_program_version; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
28504: binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `argp_program_version' [GLIBC_2.2.5]
28504: symbol=__d
相似文章
如何编写共享库(2011)
Ulrich Drepper 于 2011 年撰写的经典参考文献《如何编写共享库》,涵盖了 Linux 平台上的 ELF、ABI、符号版本控制以及动态链接的最佳实践。这是一篇被 Linux 开发者广泛引用的系统编程基础性文档。
动态链接最佳实践(2021)
本文介绍了在UNIX-based系统中动态链接和共享库的最佳实践,涵盖版本管理、链接器、加载器以及可移植实现策略。
EpicGames/raddebugger
Epic Games 开源了 RAD Debugger——一款原生 Windows 用户模式图形调试器,同时开源了 RAD Debug Info(RDI)格式以及高性能 RAD Linker,后者面向 x64 PE/COFF 二进制文件,针对拥有数 GB 级调试信息的超大型项目进行了优化。
在dsymutil中采用并行DWARF链接器
苹果的dsymutil工具用于将DWARF调试信息链接到自包含的捆绑包中,现在正在采用并行DWARF链接器来解决类型去重中的单线程瓶颈,尽管由于输出并非二进制完全相同而在验证方面面临挑战。
在现代 glibc 上剖析 House of Apple 2
本文剖析了在现代 glibc 版本上的 House of Apple 2 利用技术,提供了交互式 GDB 演练,并通过沙箱环境分析了其可行性。