使用静态编译时,只有程序实际需要的库的功能才链接到程序。如何使用共享库?只有程序实际需要的函数是由动态链接器加载到内存中的,还是总是加载了总共享库?如果它是函数,我如何在运行时获得程序的实际大小,包括其加载的函数?
谢谢! 奥利弗
答案 0 :(得分:6)
使用静态编译,只有程序实际需要的库的功能才链接到程序。如何使用共享库?
程序以符号方式引用共享库,即程序将按名称标识与其链接的共享库。
只有程序实际需要的函数是由动态链接器加载到内存中的,还是总是加载了总共享库?
该程序将引用共享库中的特定入口点和数据对象。共享库将作为单个大对象映射到内存中,但只有实际引用的页面才会被内核分页。加载的库的总量将取决于引用的密度,链接到它的其他图像的引用,以及库自身功能的位置。
如果是函数,我如何在运行时获取程序的实际大小,包括其加载的函数?
Mac和其他基于Unix的系统的最佳方法是 ps(1)。
答案 1 :(得分:2)
当您静态链接时,只有(可能)调用的函数会链接到可执行文件中 - 但在运行时,可执行文件中的数据将通过请求分页读入内存。
创建进程时,会将地址分配给该进程的可执行文件和共享库中的所有代码,但此时文件中的代码/数据不一定会读入物理内存。当您尝试访问当前不在物理内存中的地址时,它将触发一个不存在的异常。操作系统虚拟内存管理器将通过将文件从文件读入物理内存来对此做出反应,而不是让访问继续进行。
加载是在逐页的基础上完成的,这通常意味着一次为4或8千字节的块(例如,x86使用4K页,Alpha使用8k)。 x86还具有创建更大(4兆字节)页面的能力,但这些页面不是(至少通常)用于普通代码 - 它们用于映射仍然映射(半)永久映射的大块内存,例如作为典型图形卡上内存的“窗口”,它也被映射,因此可由CPU直接访问。
大多数加载器都有一些优化,所以(例如)它们会在程序最初启动时尝试读取更大的内存块。这使得它的启动速度比在每次访问代码时都有中断和单独读取时更快。该优化的确切细节因操作系统(通常甚至是相同操作系统的版本)而异。