我正在搜索有关使用运行时链接程序加载程序时发生的运行时间开销的一些统计信息(例如ld.so
)。我不是运行时链接器如何工作的专家,但据我所知,它通常执行以下操作:
LD_LIBRARY_PATH
因此,当我通过GUI或命令行启动程序时,会在某个时刻发生对exec
的系统调用,并启动所请求的程序。让我们快速看看会发生什么:
Exec(myprogram)
myprogramm
加载到内存_start
main()
被称为假设上面的列表是正确的,我没有遗漏任何重大步骤,我会对两件事感兴趣:
答案 0 :(得分:3)
假设上面的列表是正确的
正如this answer所解释的那样,这并不完全正确。
根据理论,步骤4的开销是多少?
取决于和变化。
扮演角色的一些因素:
该程序链接了多少个动态库?
加载几十个图书馆的情况并不少见。
当有5000个或更多的图书馆时dramatically slow down。
程序引用了多少数据和函数符号?
必须在加载时解析数据引用,但可以懒惰地解析函数符号。 (有关延迟符号解析here的更多信息。)
如何在实践中确定步骤4的开销(例如,对于Firefox或Chrome等真实程序)?
使用GLIBC,只需在环境中设置LD_DEBUG=statistics
即可。例如:
LD_DEBUG=statistics /bin/date
104984:
104984: runtime linker statistics:
104984: total startup time in dynamic loader: 1348294 clock cycles
104984: time needed for relocation: 501668 clock cycles (37.2%)
104984: number of relocations: 90
104984: number of relocations from cache: 3
104984: number of relative relocations: 1201
104984: time needed to load objects: 413792 clock cycles (30.6%)
Sun Dec 11 17:51:35 PST 2016
答案 1 :(得分:0)
粗略估计,编写两个测试程序:一个静态程序和一个使用动态库的程序(变体:只有C运行时动态库)。然后测量开始时间的差异。如果两个程序的大小相当,则差异可归因于动态加载。
答案 2 :(得分:0)
Exec(myprogram)
- 操作系统将
myprogramm
加载到内存- 操作系统将执行权转交给
_start
- 发生了一些初始化并运行了运行时链接程序
- 醇>
main()
被称为假设上面的列表是正确的,我没有遗漏任何内容 主要步骤
实际上这不是正确的列表,至少对于Linux而言。
主要说明:动态链接器(将所需库映射到的程序)
进程地址空间在程序获得控制之前运行。 ELF部分带有动态链接器的路径,通常类似于/lib/ld-linux.so.2
,并且该程序在真正的程序之前得到控制,并且它可以加载"共享库。
次要注意:"加载到内存中#34;事实上并非如此,实际上文件中的可执行文件和共享库文件映射到进程的地址空间,下一代4K代码/数据按需加载(4K是常见的内存页面大小)。控制_start也不完全正确,传递执行控制的点是从ELF头获取的,通常是" _start"符号指向此地址,但我想您可以创建ELF文件,无需" _start"符号
我会对两件事感兴趣:
- 根据理论,步骤4的开销是多少?
- 如何在实践中确定步骤4的开销(例如,对于Firefox或Chrome等真实程序)?
醇>
正如我所写,在第4步动态链接器没有运行,实际上如果你使用firefox或chrome程序,你无法测量ld-linux.so.2的工作时间,因为它在firefox / chrome的任何指令之前运行可执行程序控制了。
你可以编辑firefox的可执行文件并将/lib/ld-linux.so.2替换为/lib/ld-linux.so。 3 ,然后破解glibc(ld-linux.so部分)它用来衡量它的时间。
在main
之前运行的所有其他代码,我认为您可以正常方式进行分析,
例如:What is a good easy to use profiler for C++ on Linux?