计算机共享文件的代码重用

计算机的目标文件通常分成三类:
可重定位目标文件:包含二进制代码,编译时可以与其他目标文件结合,创建一个可执行目标文件。
可执行目标文件:包含完整的二进制代码和数据,可以直接复制到内存中并执行。它们是独立运行的程序,不需要其他文件的支持。
共享目标文件:一种特殊的可重定位目标文件,可以在加载或运行时被动态加载到内存并与其他共享目标文件链接。它们允许多个程序共享相同的代码和数据。
前面的文章介绍了《可重定位目标文件》,解释了它是经过几个步骤最终形成了「可执行目标文件」,那么 … 
什么是可执行目标文件?
可执行目标文件是编程的最终成果,它是一个二进制文件,包含从「加载」到「运行」所需要的全部信息,在我们将要执行文件的时候,会把文件内容复制到内存,然后执行它。
可执行目标文件是我们应用程序的最终形式,它让计算机能够理解、加载和运行我们的代码,就像打开一本书一样。

上面说的转移到程序的开头,就比喻成一本书的第一页,它来告诉计算机从哪里开始执行程序。
ELF头:就像书的封面,提供了一些关于这个可执行文件的基本信息;
.init:一个特殊的部分,里面包含了一些初始化程序需要的信息;
.text:是程序真正的开头,就像书的第一页一样。这里包含了程序的实际代码,计算机会从这里开始执行程序;
.symtab:就像书中的索引或者目录,它包含了程序中使用的符号(比如函数名、变量名)和它们在文件中的位置的信息。
.debug:这部分包含了调试信息,就像一本书的草稿或者注释,用来帮助程序员在调试时理解程序的运行情况。
节头部表:包含了文件的元信息,类似于书的目录页。它告诉计算机如何解释文件的各个部分,包括各个小节的起始和结束位置等信息。
文件如何执行?
文件通过加载器执行,加载器将可执行文件中的代码和数据从磁盘复制到内存中,然后通过跳转到程序的第一条指令或入口点来运行该程序,这个复制到内存并运行的过程,称为「加载」。
加载完成后,程序会初始化执行环境,执行一些必要的准备工作,它跳转到程序的入口点,通常是用户层的 main 函数,从这里开始执行程序逻辑。
在程序执行过程中,它可能会与操作系统交互,执行各种操作,直到程序完成其任务。当程序执行完毕或者需要返回一些结果给操作系统时,控制权会被返回给操作系统,程序的执行结束。
什么是共享目标文件
共享目标文件也称为「共享库」,共享库是为了解决静态库的一些缺陷而设计的。在运行或加载时,共享库可以被加载到任意内存地址,并与内存中的多个程序链接在一起,这个过程称为「动态链接」。
共享库的一个主要目的是允许多个进程共享同一个库代码的副本,以节省计算资源。但是,多个进程如何共享一个程序的副本呢?
一种方法是为每个共享库分配一个预先准备好的专用地址空间片段,然后要求加载器总是将共享库加载到这个地址。尽管这种方法很简单,但它不够高效,因为即使一个进程不使用共享库,分配给它的地址空间片段仍然会占用内存。
此外,管理这些分配的片段也比较复杂,如果库的大小发生变化,就需要找到一个新的适合大小的地址片段。
现代系统采用了另一种不同的方法,这种方法允许共享库加载到任何位置而无需修改链接器。这样,无数个进程都可以共享一个代码段的副本,这种代码称为「位置无关代码」,这种代码的特点是它不依赖于固定的内存地址,因此可以在不同的内存位置运行而不会出现问题。
概括来说:位置无关代码的原理是使用相对寻址、全局偏移表、过程链接表以及重定位等技术,使代码不依赖于特定的内存位置,从而能够在不同的内存位置加载和运行。这些技术使得代码更具可移植性和灵活性。
共享库的应用
在 web 服务器上,共享库发挥着关键作用。它的应用方式是将每个生成动态内容的函数打包到共享库中。
当来自Web浏览器的请求时,服务器可以动态地加载和链接这些函数,然后直接调用它们。这些函数会一直缓存在服务器的地址空间中,因此只需付出一次简单的函数调用开销,就可以重复使用它们。
这对于一个繁忙的网站来说至关重要。它意味着在服务器运行时,不需要停止服务器就可以更新已经存在的函数或添加新函数。这种动态加载和重用功能使得服务器能够在不中断服务的情况下进行升级和扩展,确保网站的高可用性和性能。
可以将共享库理解成「插件」,许多应用程序和框架允许开发人员编写插件,这些插件通常以共享库的形式提供,这样使得应用程序可以在运行时加载和卸载插件,以增加功能或修改行为。

题图生成:Pixabay
内容优化:ChatGPT
内容来源:《深入理解计算机系统》

原创文章,作者:小道研究,如若转载,请注明出处:https://www.sudun.com/ask/34521.html

(0)
小道研究's avatar小道研究
上一篇 2024年4月13日 下午10:17
下一篇 2024年4月13日 下午10:19

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注