GNU Dynamic Loader search directories

The GNU dynamic loader is one of the main components of the user space in Linux based systems (file name: /lib/ld-linux.so.2). Whenever a program is executed, the dynamic loader is loaded into the process’ address space and called by the kernel before the control is passed to the program’s “main” function (basically, it is not the “main” function initially called by the kernel, but this knowledge is sufficient for a high-level understanding and is not part of the dynamic loader internals). The main task of the dynamic loader is to handle the interaction between the program and the system’s shared libraries by relocating unresolved symbols.To keep the programs as portable as possible across different GNU/Linux based systems, the program usually only records the shared library name (in fact the shared library’s internal soname to enable library versioning) while omitting the absolute path to the shared library.Before relocating unresolved symbols, the dynamic loader needs to find the appropriate shared library by searching different directories which is the focus of this short and high-leveled post.

The man page ld.so(8) [1] serves thereby as an entry point which directories are searched in which order:

  1. the DT_RPATH value of the program’s .dynamic ELF section (colon separated list of directories)
  2. the LD_LIBRARY_PATH environment variables (colon separated list of directories)
  3. the DT_RUNPATH value of the program’s .dynamic ELF section (colon separated list of directories)
  4. the dynamic loader cache file, usually /etc/ld.so.cache
  5. the default system library directories configured at compile-time, usually /lib and/usr/lib (skipped if the binary is linked with-z nodefaultlib)

(Note: the LD_PRELOAD environment variable could be used to specify shared libraries to loaded before any other shared libraries, but you need to specify the absolute library path instead of just a search directory as in the cases above)

下面分享一下关于上面这个话题的一个例子:

我编写了一个使用Mysql C API连接数据库的测试程序

#include <stdio.h>
#include <mysql.h>

int main()
{
    MYSQL mysql;

    mysql_init(&mysql);
    if (!mysql_real_connect(&mysql, "localhost", "root", "root", "test",0, NULL, 0)) 
    {   
        printf("Connect Fail!\n");
        return -1; 
    }   
    else
    {   
        printf("Connect Successfully!\n");
        mysql_close(&mysql);
        return 0;
    }   
}

首先,在/usr/lib目录下面没有libmysqlclient.so.18文件,我先执行一下 touch /usr/lib/libmysqlclient.so.18。

并且,执行 export LD_LIBRARY_PATH=/usr/lib。

第一次,我这么编译:

gcc -o mysql_client mysql_client.c -I/usr/local/mysql/include -L/usr/local/mysql/lib -lmysqlclient

运行./mysql_client 报错:

./mysql_client: error while loading shared libraries: /usr/lib/libmysqlclient.so.18: file too short

说明动态链接器ld找到的是/usr/lib 下面,刚刚创建的一个空白文件。

第二次编译:

gcc -o mysql_client mysql_client.c -I/usr/local/mysql/include -L/usr/local/mysql/lib -lmysqlclient -Wl,-rpath,/usr/local/mysql/lib

运行./mysql_client 结果:

Connect Successfully!

我们使用readelf -d mysql_client 查看一下可执行文件的动态链接段,发现有这么一个符号:

0x0000000f (RPATH)                      Library rpath: [/usr/local/mysql/lib]

第三次编译:

gcc -o mysql_client mysql_client.c -I/usr/local/mysql/include -L/usr/local/mysql/lib -lmysqlclient -Wl,-rpath,/usr/local/mysql/lib,-enable-new-dtags

运行./mysql_client 结果:

./mysql_client: error while loading shared libraries: /usr/lib/libmysqlclient.so.18: file too short

我们再来看一下可执行文件:

 0x0000000f (RPATH)                      Library rpath: [/usr/local/mysql/lib]
 0x0000001d (RUNPATH)                    Library runpath: [/usr/local/mysql/lib]

多了一个 RUNPATH。

据此可知,如果有这个符号存在,动态链接器还是会先去 LD_LIBRARY_PATH 目录中寻找所依赖的动态链接库文件。

你可能感兴趣的:(GNU Dynamic Loader search directories)