我正在生成一个在 ARM 处理器上运行的十六进制文件,我希望将其保持在 32K 以下。它目前比这个大得多,我想知道是否有人可以提供一些关于缩小它的最佳方法的建议?

这是我到目前为止所做的

  1. 因此,我对其运行“size”以确定十六进制文件有多大。
  2. 然后再次“大小”以查看链接以创建十六进制文件的每个目标文件有多大。看来大部分大小都来自外部库。
  3. 然后我使用“readelf”来查看哪些函数占用了最多的内存。
  4. 我搜索了代码,看看是否可以消除对这些函数的调用。

这就是我陷入困境的地方,有一些函数我不直接调用(例如_vfprintf),我找不到调用它的内容,因此我可以删除该调用(因为我认为我不需要它)。

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

对答案的回应:

  • 正如我所看到的,正在调用的函数占用了大量内存。然而我找不到它的名字。
  • 我想省略这些函数(如果可能的话),但我找不到调用它们的函数!我猜可以从任意数量的库函数中调用。
  • 我认为链接器正在按预期工作,它只包含相关的库文件。您如何知道是否仅包含相关功能?你可以为此设置一个标志或其他东西吗?
  • 我正在使用海湾合作委员会
有帮助吗?

解决方案

一般清单:

  • 确保禁用编译器和链接器调试选项
  • 在打开所有大小选项的情况下进行编译和链接(gcc 中的 -O)
  • 跑步 strip 在可执行文件上
  • 生成映射文件并检查函数大小。您可以让链接器生成映射文件(-M 使用 ld 时),或者您可以在最终的可执行文件上使用 objdump(请注意,这仅适用于未剥离的可执行文件!)这实际上不会解决问题,但它会让您知道最严重的问题。
  • 使用 nm 研究从每个目标文件调用的符号。这应该有助于查找谁在调用您不想调用的函数。

最初的问题是一个关于仅包含相关功能的子问题。 gcc 将包括使用的每个目标文件中的所有函数。换句话说,如果您有一个包含 10 个函数的目标文件,则所有 10 个函数都将包含在您的可执行文件中,即使实际调用了其中一个 1。

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

您没有理由不能使用同样的技巧。当然,您可能会争辩说,如果不调用这些函数,您可能可以自己删除它们。

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

其他提示

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

解释:GNU ld 链接节,并且 GCC 为每个翻译单元生成一个节,除非您另有说明。但在 C++ 中,依赖图中的节点是对象和函数。

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

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

在深度嵌入的项目中,我总是尽量避免使用任何标准库函数。即使是像“strtol()”这样的简单函数也会放大二进制文件的大小。如果可能的话,只需避免这些电话即可。

在大多数深度嵌入式项目中,您不需要通用的“printf()”或动态内存分配(许多控制器具有 32kb 或更少的 RAM)。

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

好吧,最后我只是将项目简化为最简单的形式,然后慢慢地逐个添加文件,直到我想要删除的函数出现在“readelf”文件中。然后,当我获得该文件时,我注释掉了所有内容,然后慢慢将内容添加回来,直到该函数再次弹出。所以最后我找到了它的名字并删除了所有这些调用......现在它按预期工作......甜蜜!

但一定是更好的方法。

Andrew EdgeCombe 有一个很棒的列表,但如果你真的想抓取最后一个字节, sstrip 是一个很好的工具,列表中缺少它,并且可以减少一些 kB。

例如,当运行于 strip 本身, 它可以减少约 2kB.

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

sstrip是一个小实用程序,用于删除 不属于程序内存映像一部分的ELF文件。

大多数ELF可执行文件都是使用程序头表和 section header table.但是,只有前者是必需的 操作系统加载、链接和执行程序。sstrip尝试 提取ELF标头、程序标头表及其内容, 将所有其他内容都放在位桶中。它只能移除 在要保存的零件之后,在末尾出现的文件。但是, 这几乎总是包括节标题表,偶尔 运行程序时不使用的一些随机部分。

请注意,由于它删除了一些信息,sstrip 的可执行文件是 传闻有问题 用一些工具。这在来源的评论中进行了更多讨论。

还...有趣/疯狂地阅读如何制作尽可能最小的可执行文件, 本文 值得一读。

为了满足这一特定需求:

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

如果您想分析您的代码库以了解谁调用了什么、谁正在调用给定函数等等,可以使用 SciTools 提供的一个很棒的工具,名为“Understand C”。

https://scitools.com/

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

他们提供有限时间的评估,然后您必须购买许可证。

你可以看看类似的东西 可执行压缩.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top