当前位置:  开发笔记 > 编程语言 > 正文

gcc ld:确定静态库链接顺序的方法

如何解决《gccld:确定静态库链接顺序的方法》经验,为你挑选了1个好方法。

我的可执行文件与许多静态库链接,在Linux上通常有50至100个存档。有时,这些档案中存在依赖性周期。这些库在链接命令行上出现的顺序很重要,请参见此处。尝试手动订购许多库至少要耗费大量时间,尤其是在存在循环的情况下。

问题:是否有实用程序或技术可以分析代码库并产生正确的链接命令行顺序?



1> Craig Estey..:

您想要一种拓扑排序

tsort程序将执行此操作,但是您需要做更多工作才能使用它[准备编写perl / python脚本]。同样,还有另一种方法。而且,由于我之前已经做过这类事情,所以我转到下面的“方法”。


简短的答案:使用--start-group liblist --end-group并完成它。

有几个原因:

一个ld小组很聪明。它不仅仅循环文件。它会初次通过组,但会记住符号。因此,在随后的遍历中,它将使用缓存的符号表信息,因此非常快。

对于复杂的交互,您可能无法摆脱使用拓扑排序的所有循环,因此即使对liblist进行了拓扑排序,您仍然需要一个组。

我们到底在谈论多少时间?而且,您认为可以节省多少时间?您将如何衡量事物以证明您确实需要此功能。


追求黄金

而不是使用ld,请考虑使用ld.gold。它已经从头开始重写,使用libbfd [这很慢],并且可以直接在ELF文件上运行。创建它的主要动机是简单性和速度


如何对库列表进行拓扑排序

如果这样做info coreutils,则tsort部分将提供有关如何对符号表进行拓扑排序的示例。

但是,在此之前,我们需要获取符号。对于.a文件,nm可以提供以下列表:nm -go

输出将如下所示:

libbfd.a:
libbfd.a:archive.o:0000000000000790 T _bfd_add_bfd_to_archive_cache
libbfd.a:archive.o:                 U bfd_alloc
libbfd.a:archive.o:0000000000000c20 T _bfd_append_relative_path
libbfd.a:archive.o:                 U bfd_assert
libbfd.a:archive.o:                 U bfd_bread
libbfd.a:archive.o:00000000000021b0 T _bfd_bsd44_write_ar_hdr
libbfd.a:archive.o:                 U strcpy
libbfd.a:archive.o:                 U strlen
libbfd.a:archive.o:                 U strncmp
libbfd.a:archive.o:                 U strncpy
libbfd.a:archive.o:                 U strtol
libbfd.a:archive.o:                 U xstrdup
libbfd.a:bfd.o:                 U __asprintf_chk
libbfd.a:bfd.o:00000000000002b0 T _bfd_abort
libbfd.a:bfd.o:0000000000000e40 T bfd_alt_mach_code
libbfd.a:bfd.o:                 U bfd_arch_bits_per_address
libbfd.a:bfd.o:0000000000000260 T bfd_assert
libbfd.a:bfd.o:0000000000000000 D _bfd_assert_handler
libbfd.a:bfd.o:0000000000000450 T bfd_canonicalize_reloc
libbfd.a:bfd.o:                 U bfd_coff_get_comdat_section
libbfd.a:bfd.o:0000000000000510 T _bfd_default_error_handler
libbfd.a:bfd.o:0000000000000fd0 T bfd_demangle
libbfd.a:bfd.o:                 U memcpy
libbfd.a:bfd.o:                 U strchr
libbfd.a:bfd.o:                 U strlen
libbfd.a:opncls.o:0000000000000a50 T bfd_openr
libbfd.a:opncls.o:0000000000001100 T bfd_openr_iovec
libbfd.a:opncls.o:0000000000000b10 T bfd_openstreamr
libbfd.a:opncls.o:0000000000000bb0 T bfd_openw
libbfd.a:opncls.o:0000000000001240 T bfd_release
libbfd.a:opncls.o:                 U bfd_set_section_contents
libbfd.a:opncls.o:                 U bfd_set_section_size
libbfd.a:opncls.o:0000000000000000 B bfd_use_reserved_id
libbfd.a:opncls.o:00000000000010d0 T bfd_zalloc
libbfd.a:opncls.o:00000000000011d0 T bfd_zalloc2

libglib-2.0.a:
libglib-2.0.a:libglib_2_0_la-gallocator.o:0000000000000100 T g_allocator_free
libglib-2.0.a:libglib_2_0_la-gallocator.o:00000000000000f0 T g_allocator_new
libglib-2.0.a:libglib_2_0_la-gallocator.o:0000000000000150 T g_blow_chunks
libglib-2.0.a:libglib_2_0_la-gallocator.o:0000000000000160 T g_list_push_allocator
libglib-2.0.a:libglib_2_0_la-gallocator.o:0000000000000060 T g_mem_chunk_alloc
libglib-2.0.a:libglib_2_0_la-gallocator.o:0000000000000090 T g_mem_chunk_alloc0
libglib-2.0.a:libglib_2_0_la-gallocator.o:0000000000000110 T g_mem_chunk_clean
libglib-2.0.a:libglib_2_0_la-gallocator.o:0000000000000120 T g_mem_chunk_reset
libglib-2.0.a:libglib_2_0_la-gallocator.o:00000000000001b0 T g_node_pop_allocator
libglib-2.0.a:libglib_2_0_la-gallocator.o:00000000000001a0 T g_node_push_allocator
libglib-2.0.a:libglib_2_0_la-gallocator.o:                 U g_return_if_fail_warning
libglib-2.0.a:libglib_2_0_la-gallocator.o:                 U g_slice_alloc
libglib-2.0.a:libglib_2_0_la-gallocator.o:                 U g_slice_alloc0
libglib-2.0.a:libglib_2_0_la-gallocator.o:                 U g_slice_free1
libglib-2.0.a:libglib_2_0_la-gallocator.o:0000000000000190 T g_slist_pop_allocator
libglib-2.0.a:libglib_2_0_la-gslice.o:                 U g_private_get
libglib-2.0.a:libglib_2_0_la-gslice.o:                 U g_private_set
libglib-2.0.a:libglib_2_0_la-gslice.o:                 U g_return_if_fail_warning
libglib-2.0.a:libglib_2_0_la-gslice.o:00000000000010d0 T g_slice_alloc
libglib-2.0.a:libglib_2_0_la-gslice.o:0000000000001770 T g_slice_alloc0
libglib-2.0.a:libglib_2_0_la-gslice.o:00000000000017a0 T g_slice_copy
libglib-2.0.a:libglib_2_0_la-gslice.o:00000000000017e0 T g_slice_free1
libglib-2.0.a:libglib_2_0_la-gslice.o:0000000000001ae0 T g_slice_free_chain_with_offset

因此,语法为:

::
[TDB] :: U

并且我们需要提取libname.a,符号类型(例如T,D,B,U)和symbol

我们创建文件列表。在每个文件结构中,我们都记住所有符号及其类型。不是 U [undefined symbol]的任何类型都将定义该符号。

请注意,在构建符号表时,一个库可能有多个U(在各个.o中),这些U引用其中的另一个.o定义的符号。因此,我们只记录一次符号,并且如果看到非U类型,则将其“ 升级”(例如,如果我们看到U foo并稍后看到T foo我们将foo的类型更改为T[D和B同样]。

现在,我们遍历文件列表(例如curfile)。对于文件符号表中的每个符号,如果其类型为U[undefined],我们将扫描所有文件以查找非U符号定义。如果我们发现一个(在symfile(例如)),我们可以输出tsort的依赖行: 。我们对所有文件和符号重复此操作。

请注意,这有点浪费,因为我们可以输出许多相同的文件依赖行,因为上面的代码将为每个符号生成一行。因此,我们应该跟踪输出的行,并且仅输出唯一文件对的依赖行。此外,请注意,它可能有两个foo bar bar foo。这实际上是一个循环。虽然我们只是想一个复制foo bar和/或bar foo,他们应该不是互相排斥。

好的,现在将上述输出提供给tsort,它将为我们提供所需的liblist 拓扑排序版本。

显而易见,脚本解析可能需要一些时间,因此应基于liblist的依赖项列表将tsort输出缓存在文件中,并在makefile中进行重建。


将一些.a文件转换为.o文件

如果给定的库使用其[。]文件的全部(或大部分),而不是这样做ar rv libname.a ...,请考虑这样做ld -r libname.o ...

这与创建共享库.so文件的方法类似,但是“ big” .o仍可以静态链接。

现在,您拥有一个比.a链接速度更快的.o,因为库内链接已经解决。同样,这将对依赖性周期有所帮助。

稍微扩展一下topo脚本可以告诉您哪些库适合此。

即使不能更改普通的构建makefile,“最终”顶层也可以使用.a,将其提取到.o中,或者将ld force load选项与-r一起使用以获取“ big” .o。

推荐阅读
依然-狠幸福
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有