musl libc ldso 动态加载研究笔记:动态库的搜索路径

前言

  • 在手动设置动态库的存放路径的情况下,发现 musl ldso 依旧可以加载位于 /lib 目录下的 动态共享库

  • 动态库的存放路径或者说搜索路径,是否可以手动配置?比如 Linux 上 有个配置文件可以配置,可以改变 动态库的搜索次序,musl ldso 是否也可以做到这一点?

搜索路径

  • 通过查看 musl 的代码: ldso\dynlink.c 中的 load_library 函数中实现,了解到,musl 的动态库默认是以 lib 作为前缀的,并且不能使用系统预留的 动态库名字,比如 libc.so

musl libc ldso 动态加载研究笔记:动态库的搜索路径_第1张图片

  • musl ldso 通过应用程序的 动态库依赖列表获取依赖的动态库名字,大部分是没有路径的。

musl libc ldso 动态加载研究笔记:动态库的搜索路径_第2张图片

  • 下面是动态库路径的处理:

musl libc ldso 动态加载研究笔记:动态库的搜索路径_第3张图片
musl libc ldso 动态加载研究笔记:动态库的搜索路径_第4张图片

  • 通过这里发现,当前 平台 LDSO_ARCH 如果为 aarch64 时,如果存在 /etc/ld-musl-aarch64.path 文件,就读取这个文件,获取 sys_path,也就是动态库的搜索路径

  • 动态库的搜索路径不只是一个,可以使用 : 冒号分隔多个路径,这个 sys_path 路径是有先后次序的,前面的优先搜索。

musl libc ldso 动态加载研究笔记:动态库的搜索路径_第5张图片

环境变量

  • ldso\dynlink.c 中的 __dls3 函数中,可以发现, env_path 与 env_preload 也是动态库搜索路径的环境变量,系统如果通过 setenv 设置了 LD_LIBRARY_PATH 或者 LD_PRELOAD,也会改变 musl ldso 的搜索路径的次序
		env_path = getenv("LD_LIBRARY_PATH");
		env_preload = getenv("LD_PRELOAD");
  • 当前了解到 LD_PRELOAD 设置的是动态库,这里的动态库也是使用: 冒号分隔,优先加载

  • 如果设置了 LD_LIBRARY_PATH,是动态库的搜索路径,可以是多个,: 冒号分隔,在 ldso\dynlink.c 中的 load_library 函数 发现比 系统路径执行的早。

  • 以上都没有设置,并且有了 /etc/ld-musl-aarch64.path 文件,就读取 /etc/ld-musl-aarch64.path 里面的路径作为系统动态库搜索路径

  • 如果没有 /etc/ld-musl-aarch64.path 文件,就搜索 默认的 sys_path = "/lib:/usr/local/lib:/usr/lib",这说明即使不设置, /lib 目录下的动态库可以被 musl ldso 搜索得到。

  • "/lib:/usr/local/lib:/usr/lib" 路径搜索次序为: /lib -> /usr/local/lib -> /usr/lib

LD_LIBRARY_PATH 设置方法

  • setenv("LD_LIBRARY_PATH", "/kernel:/home/lib:/hello/app", 1);,这里设置环境变量 LD_LIBRARY_PATH,这样可以搜索的路径为: /kernel -> /home/lib -> /hello/app

  • 注意 LD_LIBRARY_PATH 的设置不影响系统的动态库搜索路径,也就是 LD_LIBRARY_PATH 搜索不到,依旧去系统的动态库路径下搜索

ld-musl-aarch64.path 设置方法

  • 注意 ld-musl-aarch64.path 表示 aarch64 平台下的,不同的平台,注意名字 "/etc/ld-musl-" LDSO_ARCH ".path"

  • 测试方法: 把共享库 libt0.so 移动到其他的位置,如 /hello 目录下,此时运行 应用程序(依赖共享库 libt0.so),提示无法找到 依赖的共享库

  • 新建 /etc 目录, 在 /etc 目录下 新建 ld-musl-aarch64.path,内容 :/lib:/usr/local/lib:/usr/lib:/hello,也就是增加了 /hello 的路径

  • 此时再次运行应用程序,正常运行,发现加载的共享库位置: /hello/libt0.so

msh />./t0_test_s.elf
msh />Error loading shared library libt0.so: No such file or directory (needed by ./t0_test_s.elf)
librtthread.so : load map : 0x212000 
Error relocating ./t0_test_s.elf: t0_data_set: symbol not found
Error relocating ./t0_test_s.elf: t0_data_get: symbol not found


msh />mkdir /etc

msh />cd /etc/

msh /etc>echo /lib:/usr/local/lib:/usr/lib:/hello /etc/ld-musl-aarch64.path

msh /etc>cat ld-musl-aarch64.path
/lib:/usr/local/lib:/usr/lib:/hello


msh />./t0_test_s.elf
msh />libt0.so : load map : 0x212000 
librtthread.so : load map : 0x233000 
  /lib/librtthread.so : init_array : 0x235a60 
  /hello/libt0.so : init_array : 0x212750 
  ./t0_test_s.elf : init_array : 0x2015d0 
main : test start
main : -----------dlopen enter -----------
dl_test : ------------get-----------
dl_test : [get] ts.name = rt-smart_t0_lib_default
dl_test : [get] ts.cmd = 0xaabbccdd
dl_test : [get] ts.data = 0x8999eeff
main : -----------dlopen exit -----------
main : ------------get-----------
main : [get] ts.name = rt-smart_t0_lib_default
main : [get] ts.cmd = 0xaabbccdd
main : [get] ts.data = 0x8999eeff
main : ------------set->get-----------
main : [set-get] ts.name = t2_name_is_ok
main : [set-get] ts.cmd = 0x33559977
main : [set-get] ts.data = 0x4499aabb
main : test end

预加载库 LD_PRELOAD

  • 当前 musl ldso 支持 "LD_PRELOAD" 环境变量,可以通过 setenv("LD_PRELOAD", "/lib/aa.so:/lib/bb.so", 1); 设置需要提前加载的共享库。

小结

  • 如果应用程序共享的库有优先级,可以把优先级高的放在搜索路径的前面,可以通过配置 /etc/ld-musl-aarch64.path 文件或者设置环境变量: setenv("LD_LIBRARY_PATH", "/kernel:/home/lib:/hello/app", 1);

  • 如果几个动态库需要提前加载初始化,可以通过 设置 "LD_PRELOAD" 环境变量,这样提前加载的共享库优先加载

你可能感兴趣的:(动态加载技术,笔记,musl,ldso,搜索路径)