我是系统编程的初学者。 我的问题与动态加载和链接有关。当在程序中使用共享库时,是将整个库加载到内存还是部分库?动态链接如何在加载完成后发生,或者两者都在运行时同时发生。
答案 0 :(得分:0)
究竟发生了什么是高度平台特定的。当您运行程序时,在Linux 上发生的事情基本上是
操作系统读取ELF二进制文件标题中的字段,以查找程序所需的程序解释程序的名称。对于32位Linux二进制文件,通常为/lib/ld-linux.so.2
。
为您的程序启动程序解释程序,并从二进制文件中读取动态链接信息。除此之外,它还搜索并加载所需的动态库
您的程序已准备好运行,这包括重新定位将运行的虚拟地址的符号以及解析符号,因此如果您的程序有致电printf()
,您的二进制文件中会有一个未解析的符号 _printf
,而C库中会出现一个同名的导出符号。此符号的地址将写入二进制文件中的位置。
最后,控制权将传递给您的计划。
这只是非常粗略概述。回答您的直接问题:整个库已加载。有关详细信息,请google for the linux program interpreter。
答案 1 :(得分:0)
由于您标记了[linux],我假设您正在谈论ELF共享库。根据您的要求,我会尽可能简单。
你问,
1)整个sample.so在运行时或唯一的时候加载到内存中 我在example.c中使用的特定函数被加载到 存储器中。
基本上整个共享库被加载(实际映射)到内存中。
2)动态链接如何以及何时解析符号
动态链接器通过使用它已加载的库的知识,它们的地址和它们的符号表来执行这项工作,以解析每个动态符号引用并在应用程序的表中写入相应的地址。记忆。这可以在最初加载共享对象时或首次使用有问题的符号时执行;细节因几个因素而异。
总的来说,我知道没有比Ulrich Drepper的论文更好的参考资料" How to write shared libraries"。我不能称之为“简单"”,但它非常全面,而且可读性与主题的性质和范围一样。
答案 2 :(得分:0)
动态链接器ld.so
是负责查找和加载程序所需的动态库(也称为共享对象,因此扩展或共享库)以准备运行程序的程序,然后运行它。
正如其他贡献者所解释的那样,整个库将被加载并映射到内存(使用mmap)。
实际上,当您尝试在Linux下运行程序时,动态链接器会在之前运行,并且只有在它完成其作业之后,控制才会传递到可执行文件的入口点。
ld.so
实际上是一个由系统程序加载器运行的辅助程序,它在ELF中使用ELF共享库在可执行文件中找到指令之后实际加载并执行ld.so
程序头称为INTERP。
您可以使用
检查此类标头$ readelf -l ./myprogram
File type ELF is EXEC (executable file)
Entry point 0x8049e7d
There are 9 program header (...)
Program headers:
Type Décalage Adr. vir. Adr.phys. T.Fich. T.Mém. Fan Alignement
PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
INTERP 0x000154 0x08048154 0x08048154 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
(...)
在这种情况下,正如您从ELF标题中看到的那样,该程序将需要在ld.so
找到/lib/ld-linux.so.2
。
理解Linux下动态链接过程中发生的事情的一个很好的资源是阅读动态链接器的手册页:
http://man7.org/linux/man-pages/man8/ld.so.8.html
并使用您自己的一些程序试验动态链接器及其环境变量。
特别是,设置LD_DEBUG环境变量并运行程序,将允许您获取有关动态链接器如何在内部工作的许多信息。
$ LD_DEBUG=all ./myprogram
您可以看到程序需要哪些库,它们如何被缓存以及它们在内存中的映射位置,可执行文件中找到的符号,动态链接器在哪个版本的缓存库中找到相应的符号,...
您可以将help
传递给环境变量,以获取可能的调试信息选项列表。
在我的系统上,我明白了:
$ LD_DEBUG=help ./myprogram
Valid options for the LD_DEBUG environment variable are:
libs display library search paths
reloc display relocation processing
files display progress for input file
symbols display symbol table processing
bindings display information about symbol binding
versions display version dependencies
scopes display scope information
all all previous options combined
statistics display relocation statistics
unused determined unused DSOs
help display this help message and exit
To direct the debugging output into a file instead of standard output
a filename can be specified using the LD_DEBUG_OUTPUT environment variable.
使用它还可以帮助您解决二进制文件中的执行问题,如果您的系统具有多个.so文件版本,则执行可能会失败,并且动态链接器恰好选择了错误的文件。
答案 3 :(得分:0)
动态链接和动态加载var1 = str[i];
var1 = var1.charCodeAt();
str[i] = var1;
动态共享对象(DSO)都进入内存(mmaping是懒惰的 - 它只是一个文件到内存的关联,而内核并没有这样做需要立即解决。)
使用动态加载,您明确mmap
一个文件并使用dlopen
查找其符号。两者都可能会失败。
使用动态链接,您只需使用符号和"链接"一个共享库,由其限定名称,此时链接器将验证所有符号是否存在。然后实际链接在运行时发生,默认情况下是懒惰的。每个函数调用都表现得好像是
dlsym
动态链接的符号通常通过所谓的全局查找范围查找。 全局查找范围从可执行对象开始,然后按顺序搜索每个链接的共享库,然后以广度优先的方式搜索它们的依赖关系,直到找到第一个符号。
动态加载会创建本地查找范围。加载的对象通常也将动态链接,并且在输入正常查找范围(如果需要)之前,通常可以从全局查找范围中解析其依赖关系。本地查找范围不能用于解析全局符号,因为动态加载允许使用dlclose()卸载。
阅读https://www.akkadia.org/drepper/dsohowto.pdf了解令人难以忍受的细节。