【问题标题】:Preventing objects from being linked if they are not needed?如果不需要,防止对象被链接?
【发布时间】:2010-03-23 19:20:30
【问题描述】:

我有一个正在使用 make 构建的 ARM 项目。我正在根据我的源目录中所有 .c 和 .cpp 文件的名称创建要链接的目标文件列表。但是,如果从未使用过对象,我想将它们排除在链接之外。即使我将它们包含在要链接的对象列表中,链接器是否会自动从 .elf 文件中排除这些对象?如果没有,有没有办法生成只包含需要链接的对象的列表?

【问题讨论】:

    标签: c++ optimization linker makefile arm


    【解决方案1】:

    您必须以不同的方式编译代码,以去除未使用的函数和数据。通常所有的对象都编译成同一个符号,所以如果不使用就不能单独省略。

    将以下两个开关添加到您的编译器行: -ffunction-sections -fdata-sections 编译时,编译器现在会将各个函数和数据放入各自的部分,而不是将它们全部集中在一个模块部分中。

    然后,在您的链接器中,指定以下内容: --gc-sections 这指示链接器删除未使用的部分(“gc”用于垃圾收集)。它将垃圾收集部分文件和整个文件。例如,如果您正在编译一个对象,但在该对象中只使用了 100 的 1 个函数,它将丢弃您未使用的其他 99 个函数。

    如果您遇到找不到函数的问题(由于各种原因,例如库之间的外部变量),您可以在链接器文件 (*.ld) 中使用 .keep 指令,以防止对这些人进行垃圾收集功能。

    【讨论】:

      【解决方案2】:

      如果您使用的是 RealView,似乎是可以的。本节讨论它:

      3.3.3 未使用部分消除

      未使用的部分删除删除从未执行的代码或未执行的数据 由代码引用,来自最终图像。这种优化可以由 --remove、--no_remove、--first、--last 和 --keep 链接器选项。使用 --info 未使用 链接器选项,指示链接器生成一个未使用节的列表 被淘汰了。

      【讨论】:

        【解决方案3】:

        正如许多人所说,答案是“取决于”。以我的经验,RVCT 非常擅长去除死代码。未使用的代码和数据几乎总是会在最后的链接阶段被删除。另一方面,GCC(至少没有 LLVM 后端)在整个图像静态分析方面相当差,并且在删除未使用的代码方面做得不好(如果你的代码位于不同的部分,那你可悲了需要跳远)。您可以采取一些措施来缓解它,例如使用函数部分,它为每个函数创建一个单独的部分并启用更好的死代码剥离。

        让您的链接器为您的二进制文件生成一个映射文件,这样您就可以看到其中的内容以及被剥离的内容。

        【讨论】:

          【解决方案4】:

          根据编译器/链接器的复杂程度和优化级别,链接器不会链接未被调用的代码。

          【讨论】:

            【解决方案5】:

            您使用的是什么编译器/链接器?有些链接器会自动执行此操作,有些链接器会将该功能作为命令行选项提供。

            【讨论】:

              【解决方案6】:

              根据我的经验,许多编译器不会基于目标文件包含未使用的代码。有些可能没有此分辨率,并且将包括整个库(“因为这使构建过程更快”)。

              例如,给定一个文件junk.c,它具有三个函数:Func1Func2Func3。构建过程会创建一个目标文件junk.o,其中包含所有三个函数。如果函数Func2 没有被使用,它无论如何都会被包含,因为链接器不能从目标文件中排除一个函数。

              另一方面,给定文件:Func1.cFunc2.cFunc3.c,具有上述功能,每个文件一个。如果不使用Func2.c 中的Func2,则链接器将不包含它。

              一些链接器足够智能,可以将文件排除在库之外。但是,每个链接器的文件包含粒度(因此文件排除)不同。阅读链接器手册或联系他们的客户支持以获取确切信息。

              我建议将可疑函数移动到单独的文件中(每个文件一个函数)并重建。测量前后的代码大小。此外,Debug 和 Release 链接之间可能存在差异。 Debug 链接可能是懒惰的,只是将所有内容都放入其中,而 Release 链接则更加努力地删除未使用的代码。

              只是我的想法和经验,您的里程可能会有所不同 (YMMV)。

              【讨论】:

                【解决方案7】:

                传统上,链接器链接在命令行中明确指定的所有目标文件中,即使它们可以被省略并且程序不会有任何未解析的符号。这意味着您可以通过包含一个目标文件来故意更改程序的行为,该目标文件执行由静态初始化触发但不直接或间接从main 调用的操作。

                通常,如果您将大部分目标文件放在静态库中,并将该库与包含入口点的单个目标文件链接,则链接器只会(迭代地)挑选出有助于解决未解析符号引用的库成员原始目标文件或随后包含的目标文件,因为它解析了先前未解析的符号。

                简而言之,将您的大部分目标文件放在一个库中,然后将其与包含您的入口点的一个目标链接。

                【讨论】:

                  猜你喜欢
                  • 2015-11-24
                  • 1970-01-01
                  • 2022-11-15
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-11-04
                  • 1970-01-01
                  • 2021-12-30
                  • 1970-01-01
                  相关资源
                  最近更新 更多