动态链接器如何知道要在哪个库中搜索符号?

How does dynamic linker know which library to search for a symbol?

我正在试验 LD_PRELOAD/dlopen 并且遇到了有关符号查找的困惑。考虑以下 2 个库:

  1. libshar

shared.h

int sum(int a, int b);

shared.c

int sum(int a, int b){
    return a + b;
}
  1. libshar2

shared.h

int sum(int a, int b);

shared.c

int sum(int a, int b){
    return a + b + 10000;
}

和可执行文件bin_shared:

#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);
}

将二进制文件与 libsharlibdl 链接 我考虑了以下两种情况:

  1. LD_PRELOAD为空

程序打印 5

为什么动态链接器决定查找 libshar 中的 sum 函数,而不是 libshar2?它们都已加载并包含所需的符号:

0x7ffff73dc000     0x7ffff73dd000     0x1000        0x0 /home/me/c/build/libshar2.so
0x7ffff73dd000     0x7ffff75dc000   0x1ff000     0x1000 /home/me/c/build/libshar2.so
0x7ffff75dc000     0x7ffff75dd000     0x1000        0x0 /home/me/c/build/libshar2.so
0x7ffff75dd000     0x7ffff75de000     0x1000     0x1000 /home/me/c/build/libshar2.so
#...
0x7ffff7bd3000     0x7ffff7bd4000     0x1000        0x0 /home/me/c/build/libshar.so
0x7ffff7bd4000     0x7ffff7dd3000   0x1ff000     0x1000 /home/me/c/build/libshar.so
0x7ffff7dd3000     0x7ffff7dd4000     0x1000        0x0 /home/me/c/build/libshar.so
0x7ffff7dd4000     0x7ffff7dd5000     0x1000     0x1000 /home/me/c/build/libshar.so
  1. LD_PRELOAD = /path/to/libshar2.so

程序打印 10005。这是预期的,但我再次注意到 libshar.solibshar2.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 案例似乎在 ld.so(8) 中有解释:

LD_PRELOAD

A list of additional, user-specified, ELF shared objects to be loaded before all others. The items of the list can be separated by spaces or colons. This can be used to selectively override functions in other shared objects. The objects are searched for using the rules given under DESCRIPTION.

dlopen 不能(也不能)更改调用时已经存在的(全局)符号的定义。它只能提供以前不存在的新内容。

这个(草率的)形式化在 specification for dlopen:

Symbols introduced into the process image through calls to dlopen() may be used in relocation activities. Symbols so introduced may duplicate symbols already defined by the program or previous dlopen() operations. To resolve the ambiguities such a situation might present, the resolution of a symbol reference to symbol definition is based on a symbol resolution order. Two such resolution orders are defined: load order and dependency order. Load order establishes an ordering among symbol definitions, such that the first definition loaded (including definitions from the process image file and any dependent executable object files loaded with it) has priority over executable object files added later (by dlopen()). Load ordering is used in relocation processing. Dependency ordering uses a breadth-first order starting with a given executable object file, then all of its dependencies, then any dependents of those, iterating until all dependencies are satisfied. With the exception of the global symbol table handle obtained via a dlopen() operation with a null pointer as the file argument, dependency ordering is used by the dlsym() function. Load ordering is used in dlsym() operations upon the global symbol table handle.

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

Why does the dynamic linker decide to lookup the sum function in the libshar, not libshar2?

UNIX 上的动态 link 用户试图模拟 会发生什么 如果你 link 使用 archive ] 图书馆。

在空 LD_PRELOAD 的情况下,符号搜索 order 是(当符号被主二进制文件引用时;当符号是由 DSO 引用):主二进制文件,按照 link 行中列出的顺序直接 linked DSO,按照 dlopen 的顺序 dlopened DSO编辑

LD_PRELOAD = /path/to/libshar2.so The program prints 10005. This is expected,

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

but again I noticed that both libshar.so and libshar2.so are loaded:

为什么是惊喜?动态 linker 加载 LD_PRELOAD 中列出的所有库,然后加载您直接 link 反对的所有库(如之前的 )。