代码之家  ›  专栏  ›  技术社区  ›  Carlo C

具有动态加载的静态链接可执行文件

  •  0
  • Carlo C  · 技术社区  · 1 年前

    我不确定这是否有意义,但有可能实现静态链接的可执行文件+动态加载吗?

    换句话说:在编译/链接时,对象代码与库静态链接,但在运行时,从库中加载相关代码的内存被推迟,直到从可执行文件中实际调用/调用相关库的函数。

    这有道理吗?非常感谢。

    编辑:在我看来,动态链接实际上需要动态加载。

    0 回复  |  直到 1 年前
        1
  •  1
  •   Employed Russian    1 年前

    换句话说:在编译/链接时,对象代码与库静态链接,但在运行时,从库中加载相关代码的内存被推迟,直到从可执行文件中实际调用/调用相关库的函数。

    这个问题有点模棱两可,取决于什么 确切地 你的意思是“加载到内存中”。

    让我们考虑执行一个完全静态链接的 ./a.out Linux上的ELF二进制文件。

    这样的二进制文件有一个或多个 PT_LOAD 分段,告诉内核如何 mmap 将二进制文件写入内存。

    从某种意义上说,二进制的整个代码(包括所有库代码)都加载到内存中(例如,该代码出现在 /proc/self/maps )在的第一条指令之前 ./a.out 甚至跑步。

    然而,与 demand paging , 没有一个 的实际占用了任何物理RAM。当您访问第一条指令(位于 _start 符号) ./a.out ,有一个 page fault ,操作系统加载包含该指令的页面 事实上 加载到物理内存中并重新启动指令,从而最终执行该指令。

    同样,当您调用某个库函数时,(可能)会出现另一个页面错误,操作系统会加载被调用库函数的代码。

    (此外:可以通过调用来修改上述行为 mlock mlockall ).


    对你的问题的另一种可能的解释是“有可能吗 mmap 库代码 只有 什么时候调用库函数?".

    在这种解释中,库代码在被调用之前不会出现在进程的地址空间中。

    这是很可能做到的:您只需要替换的实际代码 library_function 带有“存根”。当调用该存根时,它将执行必要的 mmap 将库代码“实际加载”到内存中(如果尚未加载),然后跳到“实际” library_function .


    执行第二个(更复杂的)舞蹈(我能想到)的唯一原因是,如果您的操作系统缺乏需求分页(这可能意味着它不支持分页 完全 ).

    可能有一些嵌入式操作系统可以做到这一点。