【问题标题】:What's the rule of dynamic library searching for ld?动态库搜索ld的规则是什么?
【发布时间】:2017-03-15 11:45:26
【问题描述】:

Linux 将链接器时搜索路径和运行时搜索路径分开。

对于运行时搜索路径,我在其man page (8 ld.so) 中找到了ld.so 的规则:

  1. DT_RPATH
  2. 环境 LD_LIBRARY_PATH
  3. DT_RUNPATH
  4. ld.so.cache
  5. /lib, /usr/lib

但是对于链接器时搜索路径,ld 没有运气:(

Man page for ld (1 ld) 说,除了-L 选项:

搜索的默认路径集(未使用 -L 指定)取决于 ld 使用的仿真模式,在某些情况下还取决于它的配置方式。

也可以使用“SEARCH_DIR”命令在链接脚本中指定路径。以这种方式指定的目录将在链接描述文件出现在命令行中的位置进行搜索。

取决于模拟模式的“默认路径集”是否意味着“SEARCH_DIR”?

【问题讨论】:

  • misssprite,什么是“ld”?是“ld.so”,还是“ld-linux.so”或“libdl.so”? "ld-linux.so"(ELF 动态链接器/加载器)在动态 ELF 文件中注册为解释器,部分...INTERP,检查readelf -l ./dynamic_application。 PS您使用的是哪个手册页,是man7.org/linux/man-pages/man8/ld.so.8.html 还是man7.org/linux/man-pages/man1/ld.1.html 或其他?
  • 我指的是 GCC 中的 linker,而不是加载程序。我会编辑它。@osgx
  • misssprite,你对 man page 1 ld man7.org/linux/man-pages/man1/ld.1.html 的理解不正确,DT_RPATH 等用于搜索动态库(它们被命名为libSOMETHING.so,如libc.so),应用程序需要动态部分的 NEEDED 条目(检查 readelf -d ./dynamic_program 的输出)。没有名为ld.so的动态库。
  • 我知道ld.so 是 LOADER,而不是 .so 库。也许你可以帮我编辑问题以解决任何令人困惑的问题。@osgx
  • 动态库由动态加载程序 ld-linux.so 搜索(在运行时),如您在问题中所述。并且 ld-linux.so 路径(在编译+链接过程结束时)在 binutils 链接器ld(不正确)和 gcc(正确,检查gcc -dumpspecs|grep dynamic-linker)中硬编码,并从 gcc 传递到 ld(检查我的答案)。

标签: linux gcc linker ld


【解决方案1】:

misssprite,要查找特定 ELF 仿真的链接器搜索路径,只需运行 ld -m<emulation> --verbose | grep SEARCH_DIR

【讨论】:

    【解决方案2】:

    说到ld本身,库路径搜索顺序如下:

    1. 通过-L 命令行标志指定的目录
    2. LIBRARY_PATH 环境变量中的目录
    3. SEARCH_DIR 链接描述文件中的变量。

    您可以通过运行ld --verbose | grep SEARCH_DIR 查看默认链接描述文件中指定的目录。请注意,SEARCH_DIR 值中的 = 将替换为 --sysroot 选项的值(如果您指定它)。

    通常ld 不是直接调用的,而是通过编译器驱动程序将几个-L 选项传递给链接器。对于gccclang,您可以通过使用-print-search-dirs 选项调用它来打印编译器添加的其他库搜索目录。另请注意,如果您指定一些特定于机器的编译器标志(例如 -m32 作为misssprite 提到的),则链接器可能会根据所选的 ELF 仿真使用不同的链接器脚本。对于gcc,您可以使用-dumpspecs 选项来查看不同的编译器标志如何影响链接器调用。但恕我直言,查找链接器命令行的最简单方法是编译和链接一个指定 -v 的简单程序。

    【讨论】:

    • LIBRARY_PATH 对我不起作用。我编辑了问题以澄清问题。你能更新回应这两个问题吗?顺便说一句,我没有提到-m32。好像是另一个小伙伴把他的回答删了。
    • @misssprite,您尝试使用 LIBRARY_PATH 修改的确切命令是什么?我在 binutils 的 ld 源中没有看到 LIBRARY_PATH 的读取:github.com/bneumeier/binutils/…ldfile_add_library_path github.com/bneumeier/binutils/search?q=ldfile_add_library_path+ 充满了链接器脚本 (github.com/bneumeier/binutils/blob/…) 和 ld -L options github.com/bneumeier/binutils/blob/… 的 SEARCH_DIR 选项
    • @osgx,命令应该没问题,export LIBRARY_PATH=.:$LIBRARY_PATH。所以src代码也表明LIBRARY_PATH没有生效。
    • @osgx,我运行 ld hello.o -ltest -L.ld hello.o -ltest,并设置了 LIRARY_PATH。前者在 pwd 中找到了libtest.so,后者没有。
    • @osgx,是的,它是 ubuntu gnu ld。正如您之前所说,LIBRARY_PATH 不会出现在 ld 源中,它应该不会生效。这是有道理的。
    【解决方案3】:

    misssprite,在 binutils 的 ld 链接器中没有搜索 ld.sold-linux.so

    使用 gcc 构建动态程序时,它使用 ld (collect2) 程序的选项 -dynamic-linkerhttp://man7.org/linux/man-pages/man1/ld.1.html

    -Ifile,--dynamic-linker=file

      Set the name of the dynamic linker.  This is only meaningful when
           generating dynamically linked ELF executables.  The default
           dynamic linker is normally correct; don't use this unless you
           know what you are doing.")
    

    通常用作ELF的运行时加载程序,“ld-linux.so”在动态ELF文件中注册为解释器,程序头INTERP.interp),检查输出readelf -l ./dynamic_application。据我了解,此字段用于完整路径。

    当没有 gcc(直接称为 'ld' 程序)或没有给出此选项时,ld 使用硬编码字符串的完整路径到ld.so;并且这个默认值对于大多数操作系统是不正确的,包括 Linux:

    https://github.com/bneumeier/binutils/blob/db980de65ca9f296aae8db4d13ee884f0c18ac8a/bfd/elf64-x86-64.c#L510

    /* The name of the dynamic interpreter.  This is put in the .interp
       section.  */
    
    #define ELF64_DYNAMIC_INTERPRETER "/lib/ld64.so.1"
    #define ELF32_DYNAMIC_INTERPRETER "/lib/ldx32.so.1"
    

    https://github.com/bneumeier/binutils/blob/db980de65ca9f296aae8db4d13ee884f0c18ac8a/gold/x86_64.cc#L816

    template<>
    const Target::Target_info Target_x86_64<64>::x86_64_info =
     ...
      "/lib/ld64.so.1",     // program interpreter
    const Target::Target_info Target_x86_64<32>::x86_64_info =
     ...
      "/libx32/ldx32.so.1", // program interpreter
    

    正确的动态链接器/加载器路径在 gcc 的机器 spec files 中硬编码,对于 ld-linux 的 gcc -dumpspecs 命令的 grep 输出为 -dynamic-linker 选项值。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    • 2012-01-12
    • 2013-11-13
    • 1970-01-01
    • 2018-01-26
    • 1970-01-01
    • 2010-11-07
    相关资源
    最近更新 更多