我正在生成一个在ARM处理器上运行的hex文件,我想保持在32K以下。它目前比这个要大得多,我想知道是否有人可能会对减少它的最佳方法有一些建议?
这是我到目前为止所做的事情
这里是我卡住的地方,有一些我不直接调用的函数(例如_vfprintf),我找不到调用它的所以我可以删除调用(因为我认为我不需要它)。
接下来的步骤是什么?
回答答案:
答案 0 :(得分:13)
一般清单:
strip
-M
),或者可以在最终可执行文件上使用objdump(请注意,这只适用于未提取的可执行文件!)这实际上不会修复问题,但它会让你知道最严重的罪犯。nm
调查从每个目标文件调用的符号。这应该有助于找到你不想调用的函数。原始问题是一个仅包含相关功能的子问题。 gcc
将包含所使用的每个目标文件中的所有函数。换句话说,如果你有一个包含10个函数的目标文件,即使实际调用了1个函数,所有10个函数都包含在你的可执行文件中。
标准库(例如libc)将函数拆分为许多单独的目标文件,然后存档。然后将可执行文件链接到存档。 通过拆分成许多目标文件,链接器只能包含实际调用的函数。 (这假设您是静态链接)
没有理由不能做同样的伎俩。当然,您可以争辩说,如果没有调用函数,您可以自己删除它们。
如果你是静态地链接到其他库,你可以运行上面列出的工具,以确保他们遵循类似的规则。
答案 1 :(得分:5)
可能为您节省工作的另一个优化是-ffunction-sections,-Wl,-gc-sections,假设您正在使用GCC。不过,一个好的工具链不需要被告知。
说明:GNU ld链接部分,GCC每个翻译单元发出一个部分,除非你另有说明。但是在C ++中,依赖图中的节点是对象和函数。
答案 2 :(得分:2)
只需仔细检查并记录以供将来参考,但您是否使用Thumb说明?它们是普通指令的16位版本。有时您可能需要2个16位指令,因此它不会在代码空间中节省50%。
一个体面的链接器应该只需要所需的功能。但是,您可能需要编译器& linke设置包装函数用于单独链接。
答案 3 :(得分:2)
在深度嵌入的项目中,我总是尽量避免使用任何标准库函数。甚至像“strtol()”这样的简单函数也会破坏二进制大小。如果可能的话,只需避免这些电话。
在大多数深度嵌入式项目中,您不需要通用的“printf()”或动态内存分配(许多控制器具有32kb或更少的RAM)。
我使用非常简单的自定义“printf()”而不是仅使用“printf()”,此函数只能打印十六进制或十进制格式的数字而不是更多。大多数数据结构在编译时预先分配。
答案 4 :(得分:1)
好的,最后我把项目简化为最简单的形式,然后逐个慢慢添加文件,直到我想删除的功能出现在'readelf'文件中。然后,当我收到文件时,我对所有内容进行了评论,然后慢慢添加内容,直到该函数再次弹出。所以最后我发现了什么叫它并删除了所有这些调用......现在它可以按照需要运行......甜蜜!
虽然必须是更好的方法。
答案 5 :(得分:1)
Andrew EdgeCombe有一个很棒的列表,但是如果你真的想要刮掉每一个字节,sstrip是一个很好的工具,可以从列表中删除,并且可以减少几个KB。
例如,在strip
本身it can shave off ~2kB上运行时。
从旧的README(参见this间接源文件顶部的注释):
sstrip是一个小工具,用于删除内容结尾处的内容 不属于程序内存映像的ELF文件。
大多数ELF可执行文件都是使用程序头表和 节头表。但是,按顺序只需要前者 用于加载,链接和执行程序的操作系统。 sstrip试图 提取ELF头,程序头表及其内容, 将所有其他内容留在比特桶中。它只能删除部分内容 要保存的部件之后发生的文件。然而, 这几乎总是包括节头表,偶尔也包括 运行程序时未使用的一些随机部分。
请注意,由于它删除了一些信息,因此带有一些工具的sstrip可执行文件为rumoured to have issues。这将在来源的评论中进行更多讨论。
另外......有关如何制作尽可能小的可执行文件的有趣/疯狂阅读,this article值得一读。
答案 6 :(得分:0)
回答这个特定需求:
•我想省略这些功能(如果可能的话),但我找不到什么? 叫他们!!可以从任意数量的库函数调用我 猜测。
如果你想分析你的代码库以查看谁调用了什么,调用给定函数的人以及类似的东西,那么有一个很好的工具叫做#34;理解C"由SciTools提供。
我过去经常使用它来执行静态代码分析。它确实有助于确定库依赖树。它允许轻松浏览调用树以及其他内容。
他们提供限时评估,然后您必须购买许可证。
答案 7 :(得分:-1)
您可以查看类似executable compression的内容。