动态装载包括两个功能,一个是应用程序和系统的分离,第二个是动态库和内核模块的支持,两者机制相似
动态装载有两个特点:
- 位置无关码
- 进程间共享代码段,而又有独立的数据段
其中,位置无关比较容易实现,而有独立的数据段需要硬件支持才行
1.位置无关码的实现
首先,位置无关码通过引入.GOT
和 .PLT
来实现对 外部全局变量 或者 外部函数的引用,在访问.GOT
和.PLT
时用的都是相对跳转,然后再.GOT
中使用绝对跳转,其中.GOT
是在loader装载时完成的填充。由于对.GOT
和.PLT
的访问都是相对跳转,所以这里称之为位置无关码。其实位置相关的工作由loader在装载的时候做了。
2.共用代码段,独立数据段的实现(如果代码段有修改,怎么处理,如何共享)
无论是应用程序还是动态库都面临这个问题。对于应用程序,当两个进程运行同一个应用程序时,可以共享代码段,独立数据段。对于动态库,当两个应用程序都链接这个动态库时,也可以共享代码段,独立数据段。对于位置无关码,前面说了,会借助.GOT
和.PLT
来访问外部全局变量 或者 外部函数,该过程是利用的相对寻址,而且.GOT
本身就是数据段的内容,对于动态库,所有链接到动态库的进程都要有一份动态库对应的数据段(包含.GOT
表),那么问题来了,我们说代码段共享,而且访问.GOT
又是相对跳转,那么基于共享的代码段利用相对跳转,那跳转之后的.GOT
不应该都是一个吗?如何实现拥有独立的数据段,这里就需要硬件支持了。
1) 对于拥有MMU的处理器来说,我们将分配出连续的虚拟页给.so的代码段和数据段,这样就能保证相对跳转能够找到.GOT
。对于SylixOS系统,不同进程会得到不同的虚拟页地址,对于Linux系统,可能一样也可能不一样,因为每个进程都有自己独立的地址空间。以SylixOS为例,对于两个进程来讲,.so代码段和数据段拥有的虚拟地址空间是连续的,这样就能保证完成.GOT
的相对跳转,对于代码段,两个进程映射到相同的物理页面,而数据段映射到不同的物理页面。这样,就能保证代码段共享,数据段独立(无论是全局变量还是.GOT
)
2) 对于没有MMU平台,比如说C6000系列,为了支持动态加载。引入了DSBT模型
+------------+
| .so | index 1
+------------+
| .text |
+------------+
| .data FP |
+--+------+--+
| |
| |
| |
| |
+-----------+ | | +-----------+
| PROCESS 0| | | | PROCESS 1|
+-----+-----------------+ | | +-----------+
| | | index 0 | | | | index 0 |
| | +-----------+ | | +-----------+
| v | index 1 <--+-------------+ +---------------+--> index 1 |
| DSBT +-----------+ | | +-----------+
v ^ | index ...| | | | index ...|
.DATA | +-----------+ | | +-----------+
.BSS | | index 64 | | | | index 64 |
^ +-----------------+ | | +-----------+
| | | | | | |
| | ..... | | | | ..... |
| | | | | | |
+-----------+-----------+ | .so_process 0 .so_process 1 | +-----------+
| +-----------+ +-----------+ |
+--> .DATA | | .DATA <---+
+-----------+ +-----------+
| .BSS | | .BSS |
+-----------+ +-----------+
通过在进程0 和 进程1 的数据段前加入了.DSBT
数据段,该段里面每一个索引项指向了一个数据缓冲区(利用这种方法独立数据段),其中index 1代表了相应的 .so
,所有进程的.DSBT
中索引位置是一样的,也就是说一个.so
对应索引对于所有进程都是相同的,当PROCESS 0 调用 .so中的函数时,.so
中的函数会切换DP
指针,根据自身索引在PROCESS 0的DSBT
表中位置,取出该值并切换DP
指针(.so_process 0),此后对数据的访问都是基于DP指针。DP
其实就是个数据段的基地址。同理,当PROCESS 1调用.so
中的函数,也会切换DP
指针,此时DP
会指向PROCESS 1中DSBT
中index 1的位置,这样DP
就会指向PROCESS 1为.so
分配出的独立数据段(.so_process 1),这样也实现了数据段的独立。