Embedded 减小可执行文件大小的过程

Embedded 减小可执行文件大小的过程,embedded,arm,Embedded,Arm,我正在生成一个在ARM处理器上运行的十六进制文件,我希望它保持在32K以下。它现在比这个大很多,我想知道是否有人会对瘦身的最佳方法有一些建议 这是我到目前为止所做的 所以我对它运行了“size”来确定十六进制文件有多大 然后再次“调整大小”,查看链接到创建十六进制文件的每个对象文件有多大。似乎大部分的大小来自外部库 然后我使用readelf来查看哪些函数占用的内存最多 我搜索了代码,看看是否可以消除对这些函数的调用 这就是我遇到的问题,有些函数我不直接调用(例如,_vfprintf),我找不到调

我正在生成一个在ARM处理器上运行的十六进制文件,我希望它保持在32K以下。它现在比这个大很多,我想知道是否有人会对瘦身的最佳方法有一些建议

这是我到目前为止所做的

  • 所以我对它运行了“size”来确定十六进制文件有多大
  • 然后再次“调整大小”,查看链接到创建十六进制文件的每个对象文件有多大。似乎大部分的大小来自外部库
  • 然后我使用readelf来查看哪些函数占用的内存最多
  • 我搜索了代码,看看是否可以消除对这些函数的调用
  • 这就是我遇到的问题,有些函数我不直接调用(例如,_vfprintf),我找不到调用它的内容,所以我可以删除调用(因为我认为我不需要它)

    那么接下来的步骤是什么

    对答复的答复:

    • 正如我所看到的,调用的函数占用了大量内存。然而,我找不到什么叫它
    • 我想省略这些函数(如果可能的话),但我找不到调用它们的内容!可以从任意数量的库函数调用
    • 链接器按预期工作,我认为,它只包括相关的库文件。您如何知道是否只包含相关功能?你能为那件事插个旗子什么的吗
    • 我正在使用GCC

    您可以查看类似的内容。

    只是为了再次检查并记录以供将来参考,但您是否使用拇指指示?它们是普通指令的16位版本。有时您可能需要2条16位指令,因此它不会节省50%的代码空间


    一个好的链接器应该只具有所需的功能。但是,您可能需要编译器和链接设置来打包单个链接的函数。

    好的,所以最后我只是将项目简化为最简单的形式,然后慢慢地逐个添加文件,直到要删除的函数出现在“readelf”文件中。然后,当我有了这个文件后,我把所有的东西都注释掉,然后慢慢地把东西添加回去,直到函数再次弹出。所以最后我找到了它的名字并删除了所有的电话…现在它可以正常工作了…太棒了

    但必须是一种更好的方法。

    常规列表:

    • 确保已禁用编译器和链接器调试选项
    • 在所有大小选项都打开的情况下编译和链接(-gcc中的Os)
    • 在可执行文件上运行
      strip
    • 生成映射文件并检查函数大小。您可以让链接器生成映射文件(
      -M
      当使用ld时),也可以在最终的可执行文件上使用objdump(注意,这只适用于未压缩的可执行文件!)这实际上不会解决问题,但会让您知道最坏的违规者
    • 使用
      nm
      调查从每个对象文件调用的符号。这将有助于找到谁在调用您不希望调用的函数
    原来的问题是关于只包括相关职能的子问题<代码>gcc将包括所使用的每个对象文件中的所有函数。换句话说,如果您有一个包含10个函数的对象文件,那么所有10个函数都包含在可执行文件中,即使实际调用了一个1

    标准库(如libc)将函数拆分为许多单独的对象文件,然后归档。然后将可执行文件链接到归档文件。 通过将链接器拆分为多个对象文件,链接器只能包含实际调用的函数。(假设您是静态链接)

    没有理由你不能做同样的把戏。当然,您可能会争辩说,如果不调用函数,您可能可以自己删除它们


    如果您是针对其他库进行静态链接,您也可以在这些库上运行上面列出的工具,以确保它们遵循类似的规则。

    另一个可能节省您工作的优化是-ffunction节,-Wl,-gc节,假设您使用的是GCC。不过,一个好的工具链不需要被告知这一点


    说明:GNULD链接节,GCC每个翻译单元发送一节,除非您另有说明。但是在C++中,DENDEXY图中的节点是对象和函数。在深入嵌入的项目中,

    < P>总是试图避免使用任何标准库函数。即使像“strtol()”这样的简单函数也会放大二进制大小。如果可能的话,尽量避免打那些电话

    在大多数深度嵌入的项目中,您不需要多功能的“printf()”或动态内存分配(许多控制器的RAM不超过32kb)


    我使用了一个非常简单的自定义“printf()”,而不是仅仅使用“printf()”,这个函数只能打印十六进制或十进制格式的数字,不能打印更多。大多数数据结构都是在编译时预先分配的。

    Andrew EdgeCombe有一个很好的列表,但是如果您真的想刮除最后的每个字节,它是一个很好的工具,但是列表中缺少了这个工具,并且可以节省更多的kB

    例如,在
    strip
    本身上运行时

    来自旧自述文件(请参阅间接源文件顶部的注释):

    sstrip是一个小型实用程序,它可以删除文件末尾的内容 不是程序内存映像一部分的ELF文件

    大多数ELF可执行文件都是使用程序头表和 节标题表。然而,只有前者才是必要的 让操作系统加载、链接和执行程序。sstrip试图 提取ELF头、程序头表及其内容, 把其他的东西都放在桶里。它只能移除零件 在要保存的零件之后的末尾出现的文件。然而, 这几乎总是包括节标题表