代码之家  ›  专栏  ›  技术社区  ›  ereOn

了解动态链接在UNIX上的工作原理

  •  25
  • ereOn  · 技术社区  · 14 年前

    我们有以下情况:

    • 一个名为 program 这取决于 libfoo.so
    • 这完全取决于 libstdc++

    程序

    突然之间, libfoo func_bar() 由另一个库提供的功能 libbar.so .

    李福索 利巴.so 程序 李福索 .

    现在当我执行的时候 它抱怨说他找不到 函数条()

    以下是我的问题:

    • 李福索 程序 不得不 明确地 利巴.so
    • 依赖树不是递归的吗?我想从那以后 取决于 利巴.so , 利巴.so 会自动添加到 程序 , ldd program 表明事实并非如此。

    看起来很奇怪 重新编译(重新链接)每个二进制文件

    5 回复  |  直到 14 年前
        1
  •  17
  •   caf    14 年前

    当你没有联系 libfoo.so libbar . 编译可执行文件时,默认情况下链接器不允许您保留未定义的引用。但是,在编译共享库时 libfoo 可以使用导出的函数 program 本身-当您尝试运行它时,动态链接器期望 func_bar() 由提供 程序 . 这个问题的说明如下:

    ( foo.c

    export LD_RUN_PATH=`pwd`
    gcc -Wall -shared foo.c -o libfoo.so
    gcc -Wall -L. p.c -lfoo -o p
    

    在这一点上, ./p 如您所料,运行正常。然后我们创造 libbar.so 食品

    gcc -Wall -shared bar.c -o libbar.so
    gcc -Wall -shared foo.c -o libfoo.so
    

    在这一点上, 给出您描述的错误。如果我们查一下 ldd libfoo.so ,我们注意到 依赖于 -这就是错误。要更正错误,我们必须链接 正确地:

    gcc -Wall -L. -lbar -shared foo.c -o libfoo.so
    

    再次正确运行,并且 显示依赖于 .

        2
  •  8
  •   Tobias    14 年前

    运行ldconfig告诉系统libfoo应该在哪里查找libbar。

    ldconfig查找/lib、/usr/lib和/etc/ld.so.conf中列出的任何目录。

    每个命令的手册页上都提供了详细信息。

    下面是一个使用共享库的应用程序示例。
    程序.cc

    #include "foo.h"
    #include <iostream>
    
    int main(int argc, char *argv[])
    {
        for (int i = 0; i < argc; ++i) {
            std::cout << func_foo(argv[i]) << std::endl;
        }
    }
    

    食物

    #ifndef FOO_H
    #define FOO_H
    #include <string>
    std::string func_foo(std::string const &);
    #endif
    

    foo.cc公司

    #include "foo.h"
    
    std::string func_foo(std::string const &arg)
    {
        return arg + "|" + __func__;
    }
    

    #ifndef BAR_H
    #define BAR_H
    #include <string>
    std::string func_bar();
    #endif
    

    钢筋混凝土

    #include "bar.h"
    
    std::string func_bar()
    {
        return __func__;
    }
    

    使用libfoo.so作为共享库构建。
    g++-Wall-Wextra-fPIC-共享foo.cc-o libfoo.so

    ldd程序
    ...

    更新/etc/ld.so.cache

    ldd显示动态链接器找到libfoo.so
    ldd程序
    ...


    新foo.cc

    #include "foo.h"
    #include "bar.h"
    
    std::string func_foo(std::string const &arg)
    {
        return arg + "|" + __func__ + "|" + func_bar();
    }
    

    构建libbar.so并重建libfoo.so
    g++-墙-Wextra-fPIC-shared bar.cc-o libbar.so
    g++-Wall-Wextra-fPIC-shared libbar.so foo.cc-o libfoo.so
    ldd libfoo.so公司
    ...

    ldd程序
    ...
    libfoo.so=>/主页/tobias/projects/stubs/so/libfoo.so(0x00007f49236c7000)
    libbar.so=>未找到
    这表明动态链接器仍然可以找到libfoo.so,但找不到libbar.so

    sudo ldconfig/home/tobias/projects/stubs/so/
    ldd libfoo.so公司

    libbar.so=>/主页/tobias/projects/stubs/so/libbar.so(0x00007f935e0bd000)


    ...
    libfoo.so=>/主页/tobias/projects/stubs/so/libfoo.so(0x00007f2be4f11000)

    找到libfoo.so和libbar.so。

    如果你真的很严格的话,运行ldconfig就是重新链接。 奇怪与否链接器需要知道它链接的库的依赖关系。 有很多其他的方法来实现这一点,但这是被选择的。

        3
  •  2
  •   Björn Pollex    14 年前

    LD_DEBUG=文件程序

    "How to write shared (ELF) libraries" (pdf)(无论是否使用glibc)

        4
  •  1
  •   vitaut    14 年前

    我认为这个问题是由于没有具体说明 libbar.so 作为 libfoo.so 我不确定您使用的是什么构建系统,但在CMake中可以执行以下操作:

    add_library(bar SHARED bar.c)
    
    add_library(foo SHARED foo.c)
    target_link_libraries(foo bar)
    
    add_executable(program program.c)
    target_link_libraries(program foo)
    

    program 仅与 foo ( 李福索 bar ( 利巴.so

    或者可能是 找不到。尝试在中指定其目录的路径 LD_LIBRARY_PATH

        5
  •  1
  •   Brad    14 年前

    这不应该是这样的,除非关于bar函数 符号