Linux共享库加载并与其他进程共享代码

Linux共享库加载并与其他进程共享代码,linux,memory-management,linux-kernel,shared-libraries,dynamic-linking,Linux,Memory Management,Linux Kernel,Shared Libraries,Dynamic Linking,假设我有一个共享库a.so,它是我的可执行文件第一次加载的。我的理解是,在VMA的中间,共享库文本部分被映射。我有两个问题, 1 ld.so是否要将此共享内存文本部分页面加载到物理内存,然后映射到该进程的VMA 2假设启动了第二个可执行文件,该文件使用相同的共享库a.so。ld.so是否要标识此共享库已加载到物理内存?如何理解这一点呢?准确地说,它不是ld。因此,保留物理内存或管理或选择虚拟内存和物理内存之间的映射是内核的工作。当ld.so加载共享库时,它通过mmap系统调用来加载,内核分配所需

假设我有一个共享库a.so,它是我的可执行文件第一次加载的。我的理解是,在VMA的中间,共享库文本部分被映射。我有两个问题,

1 ld.so是否要将此共享内存文本部分页面加载到物理内存,然后映射到该进程的VMA

2假设启动了第二个可执行文件,该文件使用相同的共享库a.so。ld.so是否要标识此共享库已加载到物理内存?如何理解这一点呢?

准确地说,它不是ld。因此,保留物理内存或管理或选择虚拟内存和物理内存之间的映射是内核的工作。当ld.so加载共享库时,它通过mmap系统调用来加载,内核分配所需的物理内存1,并在库文件和物理内存之间创建虚拟映射。然后,mmap返回的是映射库的虚拟基址,动态加载程序将使用该虚拟基址作为对该库函数的服务调用的基址

ld.so是否要标识此共享库已加载到物理内存?如何理解这一点

它不是ld.so,而是要识别它的内核。这是一个复杂的过程,但为了简单起见,内核会跟踪哪个文件映射到哪里,并且可以检测何时请求再次映射已映射的文件,如果可能的话,可以避免物理内存分配

如果同一文件(即具有相同路径的文件)被多次映射,内核将查看现有映射,如果可能,它将重用相同的物理页以避免浪费内存。因此,理想情况下,如果一个共享库被多次加载,那么它只能被物理分配一次

但实际上并不是那么简单。由于也可以写入内存,显然,只有当需要共享的页面与文件的原始内容保持不变时,才会发生物理页面的共享,否则映射同一文件或库的不同进程会相互干扰。这基本上适用于代码部分。文本,因为它们通常是只读的,而其他类似的部分,如只读数据。如果RW段未修改2,也可能发生这种情况。因此,简而言之,已加载库的.text段通常只分配到物理内存中一次

1实际上,内核首先创建映射,然后仅当进程试图通过映射读取或写入物理内存时才分配物理内存。这可以防止在不需要时浪费内存

2这种共享物理内存的技术是通过一种机制来管理的,在这种机制中,内核最初映射干净的页面,并在写入时将其标记为脏页,然后根据需要进行复制。

准确地说,这不是ld。因此,保留物理内存或管理或选择虚拟内存和物理内存之间的映射是我们的工作,这是内核的工作。当ld.so加载共享库时,它通过mmap系统调用来加载,内核分配所需的物理内存1,并在库文件和物理内存之间创建虚拟映射。然后,mmap返回的是映射库的虚拟基址,动态加载程序将使用该虚拟基址作为对该库函数的服务调用的基址

ld.so是否要标识此共享库已加载到物理内存?如何理解这一点

它不是ld.so,而是要识别它的内核。这是一个复杂的过程,但为了简单起见,内核会跟踪哪个文件映射到哪里,并且可以检测何时请求再次映射已映射的文件,如果可能的话,可以避免物理内存分配

如果同一文件(即具有相同路径的文件)被多次映射,内核将查看现有映射,如果可能,它将重用相同的物理页以避免浪费内存。因此,理想情况下,如果一个共享库被多次加载,那么它只能被物理分配一次

但实际上并不是那么简单。由于也可以写入内存,显然,只有当需要共享的页面与文件的原始内容保持不变时,才会发生物理页面的共享,否则映射同一文件或库的不同进程会相互干扰。这基本上适用于代码部分。文本,因为它们通常是只读的,而其他类似的部分,如只读数据。如果RW段未修改2,也可能发生这种情况。因此,简而言之,已加载库的.text段通常只分配到物理内存中一次

1实际上,内核首先创建映射,然后 仅当进程试图通过映射读取或写入物理内存时,才分配物理内存。这可以防止在不需要时浪费内存


2这种共享物理内存的技术是通过一种机制来管理的,在这种机制中,内核最初映射干净的页面,并在写入时将其标记为脏页面,根据需要进行复制。

Linux共享库通常是位置独立的,因此由于地址空间随机化,可执行文件也是位置独立的。位置独立代码使用GOT和PLT重定位机制在运行时定位所有具有外部链接的符号

当dynamic linker ld.so加载与位置无关的可执行文件或共享库时,进程内存中只能修改GOT和PLT段。带有代码的文本段以只读方式映射到进程内存中。当另一个进程加载相同的可执行文件或共享库时,它最终映射相同的页面框架,其中.text段已经由其他进程加载,但没有特定于进程地址空间布局的GET和PLT

因此,加载elf文件时,mmapNULL、text_segment_len、PROT_EXEC|PROT_READ、MAP_SHARED、elf_file_fd、text_segment_offset实际上都是这样。这将在第一次访问时填充内核,以便进行此调用的另一个进程映射页面缓存中已经存在的页面帧


有关更多信息,请参阅。

Linux共享库通常是位置独立的,因此由于地址空间随机化,可执行文件也是位置独立的。位置独立代码使用GOT和PLT重定位机制在运行时定位所有具有外部链接的符号

当dynamic linker ld.so加载与位置无关的可执行文件或共享库时,进程内存中只能修改GOT和PLT段。带有代码的文本段以只读方式映射到进程内存中。当另一个进程加载相同的可执行文件或共享库时,它最终映射相同的页面框架,其中.text段已经由其他进程加载,但没有特定于进程地址空间布局的GET和PLT

因此,加载elf文件时,mmapNULL、text_segment_len、PROT_EXEC|PROT_READ、MAP_SHARED、elf_file_fd、text_segment_offset实际上都是这样。这将在第一次访问时填充内核,以便进行此调用的另一个进程映射页面缓存中已经存在的页面帧


有关更多信息,请参阅。

谢谢。那么,当加载第二个进程时,是ld.So还是内核标识a.So的.text节已经在物理内存中可用?@FrancM为您添加了mmap注释。@EmployedRussian感谢您的评论,将节替换为段。但是.text不是段。这是一个位于荷载类型段中的截面。谢谢。那么,当加载第二个进程时,是ld.So还是内核标识a.So的.text节已经在物理内存中可用?@FrancM为您添加了mmap注释。@EmployedRussian感谢您的评论,将节替换为段。但是.text不是段。它是位于加载类型段中的一个段。@Employed俄语-如果我多次加载a.out,则物理内存中的.text段共享方式相同?@FrancM系统中的每个文件都是相同的,而不仅仅是可执行文件。对于可执行文件。文本段通常是只读的,因此这是一个很好的例子。@Employed Russian-如果我多次加载a.out,则在物理内存中共享.text段的方式是相同的?@FrancM系统中的每个文件都是相同的,而不仅仅是可执行文件。文本段通常是只读的,因此是一个很好的例子。