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

问题描述:

我正在生成一个在ARM处理器上运行的十六进制文件,我希望该文件在32K以下。它目前比这个要大得多,我想知道是否有人会对减少它的最好方法有什么建议?减少可执行文件大小的过程

这里是我到目前为止已经完成

  1. 所以我跑“大小”它来确定十六进制文件有多大。
  2. 然后'大小'再次看看有多大的每个目标文件是链接来创建十六进制文件。看起来大部分大小来自外部库。
  3. 然后我用'readelf'来查看哪些函数占用了最多的内存。
  4. 我通过代码搜索,看看我是否可以调用这些函数。

这里是我卡住的地方,有一些函数,我不直接调用(例如_vfprintf),我找不到调用它,所以我可以删除调用(因为我认为我不需要它)。

那么接下来的步骤是什么?

感谢您的帮助。

应对答案:

  • 正如我可以看到有函数被调用它占用了大量的内存。我不能找到什么叫它。
  • 我想省略这些功能(如果可能的话),但我找不到什么叫他们!我猜可以从任意数量的库函数中调用。
  • 链接器正在按照需要工作,我认为它只包含相关的库文件。你如何知道是否只包含相关功能?你能为此设置一个旗帜吗?
  • 我使用GCC
+0

也许你已经知道这一个,也许它是有帮助的:http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html – Matthias 2012-04-26 19:56:12

一般列表:

  • 请确保您有禁用
  • 编译的编译器和连接调试选项,并链接了所有大小选项开启(-Os在GCC)的
  • 运行strip可执行文件
  • 生成映射文件并检查函数大小。你可以让你的链接器生成你的映射文件(使用ld时为-M),或者你可以在最终的可执行文件上使用objdump(注意,这只适用于未被剪切的可执行文件!)这实际上并不能解决问题,但它会让你知道最坏的罪犯。
  • 使用nm来调查从每个对象文件中调用的符号。这应该有助于查找谁不想调用的调用函数。

在原来的问题是一个只包括相关功能的子问题。 gcc将包含每个使用的目标文件中的所有函数。换句话说,如果你有一个包含10个函数的目标文件,即使实际调用了1个函数,你的可执行文件中也会包含所有10个函数。

标准库(例如libc)会将函数分割成许多单独的对象文件,然后将其存档。然后将可执行文件链接到存档。 通过分割成许多目标文件,链接器只能包含实际调用的函数。 (这假设你是静态链接的)

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

如果你正在静态链接其他库,你可以运行上面列出的工具,以确保它们遵循类似的规则。

你可以看看像executable compression

+0

如果_running_程序不应该超过32K。 – 2008-10-14 11:38:54

+0

如果它一次只解压缩32k的话。 – TraumaPony 2008-10-14 14:00:35

+0

或者代码必须是可ROM的。 – 2011-07-19 16:15:34

只是仔细检查和记录以备将来参考,但是您是否使用Thumb指令?它们是正常指令的16位版本。有时您可能需要2 16位指令,因此它不会在代码空间中节省50%。

体面的链接器应该只需要所需的功能。但是,您可能需要编译器连接设置才能为单个链接打包函数。

好的,最后我把项目简化为最简单的形式,然后逐个缓慢地添加文件,直到我想删除的函数出现在'readelf'文件中。然后,当我收到文件时,我评论了所有内容,然后慢慢添加回来,直到该功能再次弹出。所以最终我发现了什么叫它,并删除了所有这些电话......现在它按需运作......甜蜜!

但必须是一个更好的方法来做到这一点。

假设您使用的是GCC,另一个可以节省工作量的优化是-ffunction-sections,-Wl,-gc-sections。尽管如此,一个好的工具链并不需要被告知。

说明:GNU ld链接部分和GCC为每个转换单元发出一个部分,除非您另有说明。但在C++中,依赖关系图中的节点是对象和函数。

在深度嵌入式项目中,我总是尽量避免使用任何标准库函数。即使像“strtol()”这样简单的函数也会破坏二进制大小。如果可能的话,只需简单地避开这些电话在最深入的嵌入式项目中,您不需要多功能的“printf()”或动态内存分配(许多控制器具有32kb或更少的RAM)。

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

Andrew EdgeCombe有一个很棒的列表,但是如果你真的想要刮掉每一个最后的字节,sstrip是一个很好的工具,从列表中缺少,并且可以削减几个kB。

例如,当在strip本身上运行时,it can shave off ~2kB

从旧的自述(参见评论在this间接源文件的顶部):

sstrip是一个小工具,其去除在 ELF文件的结尾不属于的部分的内容该程序的内存映像。

大多数ELF可执行文件都是使用程序头表和 节头表构建的。但是,只有前者需要以 的顺序才能加载,链接和执行程序。 sstrip尝试 提取ELF头,程序头表和其内容, 将所有其他内容留在位桶中。它只能删除 部分发生在最后的文件,在要保存的部分之后。然而, 这几乎总是包含部分头表,并偶尔会有几个随机部分在运行程序时不使用。

请注意,由于它删除的某些信息,带有一些工具的sstrip可执行文件是rumoured to have issues。这在源代码的评论中有更多的讨论。

另外...对于娱乐/疯狂阅读如何使尽可能小的可执行文件,this article值得一读。

要回答这个特定的需求:

•我想省略这些功能(如果可能的话),但我找不到什么 打电话给他们!可以从任意数量的库函数中调用I 的猜测。

如果您想分析您的代码库以查看谁调用了什么,调用给定函数的人以及类似的东西,那么SciTools提供了一个名为“Understanding C”的出色工具。

https://scitools.com/

我都经常用它在过去进行静态代码分析。它确实可以帮助确定库依赖树。它允许轻松浏览上下调用树等等。

他们提供有限的时间评估,那么你必须购买许可证。