我不确定这是否有意义,但是是否可以有静态链接的可执行文件+动态加载?
换句话说:在编译/链接时,目标代码与库静态链接,但是在运行时,将推迟从库中加载相关代码到内存中,直到从可执行文件实际调用/调用相关库的函数为止。
有道理吗?谢谢你。
编辑:对我来说,动态链接实际上需要动态加载。
换句话说:在编译/链接时,目标代码与库静态链接,但是在运行时,将推迟从库中加载相关代码到内存中,直到从可执行文件实际调用/调用相关库的函数为止。
这个问题有点含糊不清,取决于“加载到内存中”的“确切”含义。 让我们考虑在 Linux 上执行完全静态链接的
./a.out
ELF 二进制文件。
这样的二进制文件有一个或多个PT_LOAD
段,它们告诉内核如何将该二进制文件
mmap到内存中。 从某种意义上说,在
/proc/self/maps
的第一条指令甚至运行之前,二进制文件的整个代码(包括所有库代码)都被加载到内存中(例如,该代码出现在
./a.out
中)。但是,使用 需求分页 时,该代码中的 none 实际上不会占用任何物理 RAM。当您访问 _start
的第一条指令(位于
./a.out
符号处)时,会出现 页面错误,并且操作系统加载包含该指令的页面实际上加载到物理内存中并执行。 同样,当您调用某个库函数时,(可能)存在另一个页面错误,操作系统会加载被调用库函数的代码。
(旁白:可以通过调用
mlock 或 mlockall
来修改上述行为)。
mmap
仅在调用库函数时才使用库代码?”。
在此解释中,库代码在被调用之前不会出现在进程的地址空间中。这是很可能做到的:您只需要用“存根”替换
library_function
的实际代码即可。当调用该存根时,它将执行必要的
mmap
将库代码“实际加载”到内存中(如果尚未完成),然后跳转到“实际”library_function
。
执行第二个(更复杂的)舞蹈(我能想到的)的唯一原因是您的操作系统缺乏需求分页(这可能意味着它根本不支持分页可能有一些嵌入式操作系统可以做到这一点。