【问题标题】:Measure static memory usage for C++ ported to embedded platform测量移植到嵌入式平台的 C++ 的静态内存使用情况
【发布时间】:2013-05-25 01:32:36
【问题描述】:

我创建了一个小程序作为要在嵌入式平台上实现的系统的概念验证。该程序是用 C++11 编写的,使用 std 并编译为在笔记本电脑上运行。稍后应该实现的最终程序是嵌入式系统。我们无权访问嵌入式平台的编译器。

我想知道在将程序移植到嵌入式平台时,是否有办法以合理且可比较的方式确定程序的静态内存(编译后的二进制文件的大小)。 要求是二进制文件的大小小于 10kb。 使用以下标志编译和剥离时,我们的二进制文件大小为 700Kb:

g++ options:     -Os -s -ffunction-sections -fdata-sections
linker options:  -s -Wl,--gc-sections

strip libmodel.a -s -R .comment -R .gnu.version --strip-unneeded -R .note

在我们使用剥离和优化选项之前,它占用了 4MB。

我还有很长的路要走,而且它并不是一个真正的大项目。如何以任何方式与嵌入式平台上的等效程序进行比较。

【问题讨论】:

  • 虽然可能有一些很容易消除的膨胀,但您很有可能需要以嵌入式思维方式进行一些重大的重新架构和重写,以达到 10Kb 的目标大小。此外,您的笔记本电脑是否是静态链接的(今天通常很难做到)?如果需要嵌入式版本,那么比较也是公平的。尽管您没有提及,但大多数将您限制为 10Kb 代码的平台也有严格的 RAM 限制。
  • 每个使用和静态链接的库都会使您的最终代码膨胀。还有,这么小的app,有浮点支持吗?如果没有,还有另一个需要注意的地方。 POD 类型与数组中的类也可能会严重膨胀。我已经做了很多次这种类型的事情,下面建议的地图文件/部分是一个很好的起点。
  • 你能用-fno-rtti-fno-exceptions编译吗?这些生成的大表通常位于 PC 的磁盘上。但是,它们需要占用嵌入式设备上的 RAM/Flash。典型的节省是 10-30%,这是我上次测量的。 CPU ISA 也可以将代码大小减少/增加 +/-30%。不过,正如Chris 指出的那样,您还有一些工作要做。

标签: c++ optimization g++ embedded


【解决方案1】:

请注意,二进制文件的大小可能有点欺骗性,因为未初始化的变量(.bss 部分)不一定会占用二进制文件中的物理空间,因为这些通常只是被标记为存在而实际上没有任何空间给他们...这通常由操作系统加载程序在运行您的程序时发生。

objdump (http://www.gnu.org/software/binutils/) 或 elfdump 或 elf 工具链 (http://sourceforge.net/apps/trac/elftoolchain/) 将帮助您确定各种段、数据和文本的大小,以及各个函数的大小和全局变量等。所有这些程序“查看”您编译的二进制文件并提取大量信息,例如 .text、.data 部分的大小,列出各种符号、它们的位置和大小,甚至可以分解 .text 部分...

在 ELF 映像 test.elf 上使用 elfdump 的示例可能是 elfdump -z test.elf > output.txt。这将转储包括文本部分反汇编在内的所有内容。例如,我在系统上看到了elfdump

Section #6: .text, type=NOBITS, addr=0x500, off=0x5f168
             size=149404(0x2479c), link=0, info=0, align=16, entsize=1
             flags=<WRITE,ALLOC,EXECINSTR>
Section #7: .text, type=NOBITS, addr=0x24c9c, off=0x5f168
             size=362822(0x58946), link=0, info=0, align=4, entsize=1
             flags=<WRITE,ALLOC,EXECINSTR,INCLUDE>
....
Section #9: .rodata, type=NOBITS, addr=0x7d5e4, off=0x5f168
             size=7670(0x1df6), link=0, info=0, align=4, entsize=1
         flags=<WRITE,ALLOC>

所以我可以看到我的代码占用了多少(.text 部分)和我的只读数据。稍后在文件中我会看到...

Symbol table ".symtab"
         Value    Size     Bind Type Section                  Name
         -----    ----     ---- ---- -------                  ----
218      0x7c090  130      LOC  FUNC .text               IRemovedThisName

所以我可以看到我的函数IRemovedThisName 占用了 130 个字节。一个快速脚本将允许您列出按大小排序的函数和按大小排序的变量。这可以为您指出需要优化的地方...

对于objdump 的一个很好的例子,试试http://www.thegeekstuff.com/2012/09/objdump-examples/,特别是第3 节,它向您展示了如何使用-h 选项获取节标题的内容。

至于程序将如何在两个不同的平台上进行比较,我认为您只需在两个平台上编译并比较您在每个系统上从obj/elfdump 获得的结果 - 结果将取决于系统指令集,每个编译器的优化程度,一般硬件架构差异等。

如果您无法访问嵌入式系统,您可以尝试在笔记本电脑上使用为最终目标配置的交叉编译器。这将为您提供适合嵌入式平台的二进制文件和分析文件的工具(即objdump 的跨平台版本)。这将为您提供一些关于程序在最终嵌入式系统上的外观的大致数字。

希望这会有所帮助。

编辑:这也将有助于How to get the size of a C function from inside a C program or with inline assembly?

【讨论】:

    【解决方案2】:

    似乎包含的库占用了巨大的空间(正如评论中指出的那样),通过删除这些库,结合以下标志可以将大小减少到几乎没有:

    set(CMAKE_CXX_FLAGS "-Os -s  -ffunction-sections -fdata-sections -DNO_STD -fno-rtti -fno-exceptions")
    set(CMAKE_EXE_LINKER_FLAGS "-s -Wl,--gc-sections")  
    

    并使用以下方法删除任何不必要的代码:

    strip libmodel.a -s -R .comment -R .gnu.version --strip-unneeded -R .note
    

    4MB 可以减少到 9.4kb,低于我们的限制。

    总之,std 占用了大量空间。

    【讨论】:

      猜你喜欢
      • 2022-12-17
      • 1970-01-01
      • 2019-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-21
      • 2017-01-03
      • 2011-02-27
      相关资源
      最近更新 更多