我是靠谱客的博主 忧郁羽毛,最近开发中收集的这篇文章主要介绍《程序员的自我修养——链接、装载与库》读书笔记—— 7.6 动态链接的步骤和实现简述使用LD_DEBUG 环境变量查看动态链接器工作log附录,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

简述

动态链接可以分为以下几个步骤:

  1. 动态链接器的自举
  2. 装载共享对象
  3. 重定位和初始化

动态链接器的自举

根据前面的文章,我们知道可执行程序的so由动态链接器进行装载和重定位。但是动态链接器本身也是个so,谁来对它重定位呢?答案是它自己。动态链接器将自己重定位的这段代码过程,被称为自举(Bootstrap)。
自举过程有以下两个特殊性:
1、自举代码不可以使用全局变量,静态变量。这个比较好理解,因为.so里的全局变量,静态变量都需要重定位后才能使用。
2、自举代码不可以使用函数。这个原因其实和上边一样。使用PIC 模式编译的so,对模块内部的函数调用,也是需要使用GOT/PLT的方式,也需要先重定位才能使用。

使用LD_DEBUG 环境变量查看动态链接器工作log

使用LD_DEBUG 环境变量,可以看到动态链接器的工作过程log。如下

zqxl@ubuntu:~/work/practice/link_load_and_lib_learn/_7.5_dynamic_stuctures$ LD_DEBUG=all ./ab
# 下面是查找并装载ab 依赖的.so
20192:
20192:	file=libb.so [0];
needed by ./ab [0]
20192:	find library=libb.so [0]; searching
20192:
search path=./tls/x86_64/x86_64:./tls/x86_64:./tls/x86_64:./tls:./x86_64/x86_64:./x86_64:./x86_64:.
(LD_LIBRARY_PATH)
20192:
trying file=./tls/x86_64/x86_64/libb.so
20192:
trying file=./tls/x86_64/libb.so
20192:
trying file=./tls/x86_64/libb.so
20192:
trying file=./tls/libb.so
20192:
trying file=./x86_64/x86_64/libb.so
20192:
trying file=./x86_64/libb.so
20192:
trying file=./x86_64/libb.so
20192:
trying file=./libb.so
20192:
20192:	file=libb.so [0];
generating link map
20192:
dynamic: 0x00007f9cc735ee48
base: 0x00007f9cc715e000
size: 0x0000000000201038
20192:
entry: 0x00007f9cc715e540
phdr: 0x00007f9cc715e040
phnum:
7
20192:
20192:
... ...
# 下面开始对各个so里的符号进行重定位
20192:
20192:	relocation processing: ./liba.so (lazy)
20192:	symbol=__cxa_finalize;
lookup in file=./ab [0]
20192:	symbol=__cxa_finalize;
lookup in file=./libb.so [0]
20192:	symbol=__cxa_finalize;
lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
20192:	binding file ./liba.so [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__cxa_finalize'
20192:	symbol=g_var_a;
lookup in file=./ab [0]
20192:	symbol=g_var_a;
lookup in file=./libb.so [0]
20192:	symbol=g_var_a;
lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
20192:	symbol=g_var_a;
lookup in file=./liba.so [0]
20192:	binding file ./liba.so [0] to ./liba.so [0]: normal symbol `g_var_a'
20192:	symbol=_ITM_registerTMCloneTable;
lookup in file=./ab [0]
20192:	symbol=_ITM_registerTMCloneTable;
lookup in file=./libb.so [0]
20192:	symbol=_ITM_registerTMCloneTable;
lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
20192:	symbol=_ITM_registerTMCloneTable;
lookup in file=./liba.so [0]
20192:	symbol=_ITM_registerTMCloneTable;
lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
20192:	symbol=_ITM_deregisterTMCloneTable;
lookup in file=./ab [0]
20192:	symbol=_ITM_deregisterTMCloneTable;
lookup in file=./libb.so [0]
20192:	symbol=_ITM_deregisterTMCloneTable;
lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
20192:	symbol=_ITM_deregisterTMCloneTable;
lookup in file=./liba.so [0]
20192:	symbol=_ITM_deregisterTMCloneTable;
lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
20192:	symbol=__gmon_start__;
lookup in file=./ab [0]
20192:	symbol=__gmon_start__;
lookup in file=./libb.so [0]
20192:	symbol=__gmon_start__;
lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
20192:	symbol=__gmon_start__;
lookup in file=./liba.so [0]
20192:	symbol=__gmon_start__;
lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
... ...
# 调用每个so 的init 段中的代码
20192:	calling init: ./liba.so
20192:
20192:
20192:	calling init: /lib/x86_64-linux-gnu/libc.so.6
20192:
20192:	symbol=__vdso_clock_gettime;
lookup in file=linux-vdso.so.1 [0]
20192:	binding file linux-vdso.so.1 [0] to linux-vdso.so.1 [0]: normal symbol `__vdso_clock_gettime' [LINUX_2.6]
20192:	symbol=__vdso_getcpu;
lookup in file=linux-vdso.so.1 [0]
20192:	binding file linux-vdso.so.1 [0] to linux-vdso.so.1 [0]: normal symbol `__vdso_getcpu' [LINUX_2.6]
20192:
20192:	calling init: ./libb.so
20192:
20192:
20192:	initialize program: ./ab
20192:
20192:
# 这里应该是开始运行ab 的代码了
20192:	transferring control: ./ab
20192:
# 这里应该是延迟绑定的时候的log 输出
20192:	symbol=g_func_b;
lookup in file=./ab [0]
20192:	symbol=g_func_b;
lookup in file=./libb.so [0]
20192:	binding file ./ab [0] to ./libb.so [0]: normal symbol `g_func_b'
20192:	symbol=g_func_a;
lookup in file=./ab [0]
20192:	symbol=g_func_a;
lookup in file=./libb.so [0]
20192:	symbol=g_func_a;
lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
20192:	symbol=g_func_a;
lookup in file=./liba.so [0]
20192:	binding file ./libb.so [0] to ./liba.so [0]: normal symbol `g_func_a'
20192:
# 与init相对应的finit过程
20192:	calling fini: ./ab [0]
20192:
20192:
20192:	calling fini: ./libb.so [0]
20192:
20192:
20192:	calling fini: ./liba.so [0]

附录

/*a.c*/
int g_var_a;
void g_func_a(void)
{
g_var_a = 0x123;
}
/*b.c*/
extern int g_var_a;
static int *g_ptr_var_a = &g_var_a;
void g_func_a(void);
void g_func_b()
{
g_func_a();
g_var_a = 0x456;
g_ptr_var_a = 0;
}
/*ab.c*/
extern void g_func_b();
int main(int argc, char *argv[])
{
g_func_b();
return 0;
}
# Makefile
ab: a.c b.c ab.c
gcc a.c -fPIC -shared -g -o liba.so
gcc b.c -fPIC -shared -g -o libb.so -L. -la
gcc ab.c -no-pie -g -o ab -L. -la -lb
objdump -ds libb.so > libb.so.S

最后

以上就是忧郁羽毛为你收集整理的《程序员的自我修养——链接、装载与库》读书笔记—— 7.6 动态链接的步骤和实现简述使用LD_DEBUG 环境变量查看动态链接器工作log附录的全部内容,希望文章能够帮你解决《程序员的自我修养——链接、装载与库》读书笔记—— 7.6 动态链接的步骤和实现简述使用LD_DEBUG 环境变量查看动态链接器工作log附录所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部