C 动态链接器如何知道搜索符号的库?

C 动态链接器如何知道搜索符号的库?,c,linux,shared-libraries,dynamic-linking,C,Linux,Shared Libraries,Dynamic Linking,我正在试验LD_PRELOAD/dlopen,在符号查找方面遇到了困惑。考虑以下2个库: libshar shared.h int sum(int a, int b); int sum(int a, int b); shared.c int sum(int a, int b){ return a + b; } int sum(int a, int b){ return a + b + 10000; } libshar2 shared.h int sum(int a, in

我正在试验
LD_PRELOAD
/
dlopen
,在符号查找方面遇到了困惑。考虑以下2个库:

  • libshar
  • shared.h

    int sum(int a, int b);
    
    int sum(int a, int b);
    
    shared.c

    int sum(int a, int b){
        return a + b;
    }
    
    int sum(int a, int b){
        return a + b + 10000;
    }
    
  • libshar2
  • shared.h

    int sum(int a, int b);
    
    int sum(int a, int b);
    
    shared.c

    int sum(int a, int b){
        return a + b;
    }
    
    int sum(int a, int b){
        return a + b + 10000;
    }
    
    和可执行文件
    bin\u共享

    #include <dlfcn.h>
    #include "shared.h"
    
    int main(void){
        void *handle = dlopen("/home/me/c/build/libshar2.so", RTLD_NOW | RTLD_GLOBAL);
        int s = sum(2 + 3);
        printf("s = %d", s);
    }
    
  • LD_PRELOAD=/path/to/libshar2.so
  • 程序打印
    10005
    。这是意料之中的,但我再次注意到
    libshar.so
    libshar2.so
    都已加载:

    0x7ffff79d1000     0x7ffff79d2000     0x1000        0x0 /home/me/c/build/libshar.so
    0x7ffff79d2000     0x7ffff7bd1000   0x1ff000     0x1000 /home/me/c/build/libshar.so
    0x7ffff7bd1000     0x7ffff7bd2000     0x1000        0x0 /home/me/c/build/libshar.so
    0x7ffff7bd2000     0x7ffff7bd3000     0x1000     0x1000 /home/me/c/build/libshar.so
    0x7ffff7bd3000     0x7ffff7bd4000     0x1000        0x0 /home/me/c/build/libshar2.so
    0x7ffff7bd4000     0x7ffff7dd3000   0x1ff000     0x1000 /home/me/c/build/libshar2.so
    0x7ffff7dd3000     0x7ffff7dd4000     0x1000        0x0 /home/me/c/build/libshar2.so
    0x7ffff7dd4000     0x7ffff7dd5000     0x1000     0x1000 /home/me/c/build/libshar2.so
    
    LD\u预加载
    情况似乎在
    LD.so(8)
    中解释:

    LD\u预加载

    要加载的其他用户指定ELF共享对象的列表 在所有其他人之前。列表中的项目可以用空格分隔 或者科隆这可用于选择性地覆盖 其他共享对象。使用规则搜索对象 根据描述给出

    dlopen
    不能(也不能)更改呼叫时已存在的(全局)符号的定义。它只能提供以前不存在的新功能

    这一点的(草率)形式化体现在:

    通过调用dlopen()引入流程映像的符号可用于重新定位活动。这样引入的符号可能与程序或以前的dlopen()操作已经定义的符号重复。为了解决这种情况可能出现的歧义,对符号定义的符号引用的解析基于符号解析顺序。定义了两个这样的解析顺序:加载顺序和依赖顺序。加载顺序在符号定义之间建立顺序,以便加载的第一个定义(包括来自流程映像文件的定义和加载的任何从属可执行对象文件)优先于稍后添加的可执行对象文件(通过dlopen())。负载排序用于重新定位处理。依赖项排序使用广度优先顺序,从给定的可执行对象文件开始,然后是其所有依赖项,然后是这些文件的任何依赖项,迭代直到满足所有依赖项。除了通过使用null指针作为文件参数的dlopen()操作获得的全局符号表句柄外,dlsym()函数使用依赖项排序。加载顺序用于全局符号表句柄上的dlsym()操作

    请注意,
    LD_PRELOAD
    是非标准功能,因此此处不作描述,但在提供该功能的实现中,
    LD_PRELOAD
    以加载顺序在主程序之后但在作为依赖项加载的任何共享库之前进行操作

    为什么动态链接器决定在libshar中查找sum函数,而不是libshar2

    UNIX上的动态链接器试图模拟与存档库链接时会发生的情况

    在空
    LD_PRELOAD
    的情况下,符号搜索顺序是(当符号被主二进制文件引用时;当符号被DSO引用时,规则变得更复杂):主二进制文件,直接链接的DSO,其顺序与它们在链接行上列出的顺序相同,
    dlopen
    ed DSO,顺序为
    dlopen
    ed

    LD_PRELOAD=/path/to/libshar2.so
    程序打印10005。这是预料之中的,

    非空
    LD_PRELOAD
    通过在主可执行文件之后和任何直接链接的DSO之前插入列出的任何库来修改搜索顺序

    但我再次注意到libshar.so和libshar2.so都已加载:

    0x7ffff79d1000     0x7ffff79d2000     0x1000        0x0 /home/me/c/build/libshar.so
    0x7ffff79d2000     0x7ffff7bd1000   0x1ff000     0x1000 /home/me/c/build/libshar.so
    0x7ffff7bd1000     0x7ffff7bd2000     0x1000        0x0 /home/me/c/build/libshar.so
    0x7ffff7bd2000     0x7ffff7bd3000     0x1000     0x1000 /home/me/c/build/libshar.so
    0x7ffff7bd3000     0x7ffff7bd4000     0x1000        0x0 /home/me/c/build/libshar2.so
    0x7ffff7bd4000     0x7ffff7dd3000   0x1ff000     0x1000 /home/me/c/build/libshar2.so
    0x7ffff7dd3000     0x7ffff7dd4000     0x1000        0x0 /home/me/c/build/libshar2.so
    0x7ffff7dd4000     0x7ffff7dd5000     0x1000     0x1000 /home/me/c/build/libshar2.so
    

    为什么这是一个惊喜?动态链接器加载
    LD_PRELOAD
    中列出的所有库,然后加载您直接链接的所有库(与以前一样)。

    您提供的链接看起来像是
    dlopen
    的手册页,但与您引用的链接不同。在我的机器上,我也没有找到您在手册中引用的内容。这是旧版本吗?@SomeName:我引用的链接是定义
    dlopen
    的标准规范,而不是特定操作系统的手册页。手册页通常不太精确,但也描述了一些超出标准范围的特定于实现的行为。因此,引用中提到的
    加载顺序
    用于重新定位处理。当第一次从PLT部分调用函数时调用动态链接器时,重定位处理似乎与动态符号解析有关。这就解释了我在问题中提到的案例1……ELF标准规定了这一点。@JL2210引用一下如何?嗯。。。我的副本在车祸中丢了。让我找一个新的…当符号被DSO引用时,规则变得更复杂,从我从中得到的我们有2个符号解析顺序:加载顺序和依赖顺序。哪一个用于DSO引用的符号?无论如何,您是如何发现此解析顺序的?在我提到的规范中没有指定按链接行中列出的顺序搜索库的事实(我尝试了它,它的工作原理与您描述的完全相同)。