操作系统之后,因为从 unix 的设计结构而言,本身就是分成模块来实现一个复杂的功能的
操作系统。但这些还不是现代意义上的动态链接,原因是现代意义上的动态链接要符合两个
特点:
1、 动态的加载,就是当这个运行的模块在需要的时候才被映射入运行模块的虚拟内存
空间中,如一个模块在运行中要用到 mylib.so 中的 myget 函数,而在没有调用 mylib.so 这个
模块中的其它函数之前,是不会把这个模块加载到你的程序中(也就是内存映射),这些内
容在内核中实现,用的是页面异常机制(我可能在另一篇文章中提到这个问题)。
2、 动态的解析,就是当要调用的函数被调用的时候,才会去把这个函数在虚拟内存空
间的起始地址解析出来,再写到专门在调用模块中的储存地址内,如前面所说的你已经调用
了 myget,所以 mylib.so 模块肯定已经被映射到了程序虚拟内存之中,而如果你再调用
mylib.so 中的 myput 函数,那它的函数地址就在调用的时候才会被解析出来。
(注:这里用的程序就是一般所说的进程 process,而模块既可能是你的程序的二进制
代码,也可能是被你的程序所依赖的别的共享链接文件-------同样 ELF 格式。)
在这两点中很有点像现在的操作系统中对内存的操作,也就是只有当要用到一个内存空
间中的时候才会进行虚拟空间映射,而不是过早的把所有的空间映射好,而只有当要从这个
内存空间读的时候才分配物理空间。这有点像第一条。而只有当对这个内存空间进行写的时
候产生一个 COW(copy on write)。这就有点像第二条。
这样的好处就是充分避免不必要的开销。因为任何一个程序在运行的时候,大部分情况
下,不可能用到所有的调用函数。
这样的思想方法提出与实现都是在八十年代的 sun 公司的 SunOS 的系统上。
关于这一段历史,请你参见资料[1]。
ELF 二进制格式文件与现代的动态链接思想大致是在同一时段形成的,它的来源是
AT&T 公司的最早的 unix 中的 a.out 二进行文件格式。Bell labs 的工作人员为了使这种在 unix
的早期主要的文件格式适应当时新的软件与操作系统的要求(如 aix,SunOS,HP-UX 这样的
unix 变种,对更广泛的应用程序的扩展要求,对面向对象的支持等等),就发明了 ELF 文
件格式。
我在这里并不详细讨论 ELF 文件的具体细节,这本来就可以写一篇很长的文章,你可
以参看资料[2]来得到关于它的 ABI(application binary interface 的规范)。但在 ELF 文件所
采用的那种分层的管理方式却不仅在动态链接中起着重要的作用,而且这一思想可以说是我
们计算机中的最古老,也是最经典的思想。
评论0
最新资源