最近我意识到我的可执行文件的大小非常大。我正在使用 Eclipse 和 GCC 为 Cortex-M 微 Controller 开发软件。
为了验证这一点,我使用了在互联网上找到的一个示例项目,该项目只是通过直接操作寄存器来使 LED 闪烁,并且基于 makefile。
我使用我的库、启动代码、链接器脚本等创建了一个非常相似的项目,该项目使用 Eclipse 的托管 makefile。
第一个项目编译成功,并生成了app.txt的二进制文件。 6kB。第二个项目产生了app.48kB的二进制文件!对于本质上相同的结果来说,这显然是一个相当大的差异,而且后者绝对是一个巨大的文件,只是让 LED 闪烁。在这两种情况下,优化都已关闭。
在我自己的库中,有一些 volatile 缓冲区,这可能是大型 BSS 或数据部分的借口,因此我决定首先关注文本部分(仍然是 5 倍大,从 5kB 到 27kB) .
我查看了映射文件,以了解与二进制文件真正链接的内容。相同或相似的功能也具有相似的大小。
有一件事对我来说似乎非常非常奇怪。有些函数在整个项目中仅定义一次,但似乎已链接多次,每次都来自不同的目标文件,并且每次都占用文本部分中的空间。查看函数 .text.port_lock
的示例。
这正常吗?如何减少最终文件大小,以及如何告诉工具链每个函数仅链接一次?
编辑: 正如评论中所述,这两个程序没有不同,它是同一件事,只是做了一些小的修改(例如启动代码和访问 GPIO 寄存器的函数)。我不是在测试GCC优化代码的能力,因此我使用了-O0。我尝试理解 map 文件,以及为什么我多次看到某些功能。
最佳答案
您误读了 map 文件。没有出现 .text.port_lock
,
例如,表示 ChibiOS 函数 void port_lock(void)
的定义。
所有出现的 .text.port_lock
均引用输入链接器部分。
前 4 次出现,位于 map 文件标题为
丢弃的输入节
,指的是链接器输入的链接器节
被丢弃。例如:
.text.port_lock
0x00000000 0x1c /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chmempools.o)
表示链接器找到了大小为 28 字节的 .text.port_lock
部分
在输入文件中 /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chmempools.o)
然后把它扔掉了。
接下来的 6 次出现,位于 map 文件标题为
链接器脚本和内存映射
都引用了输入链接器部分
映射到输出 .text
部分。例如第一个:
.text.port_lock
0x000012a8 0x1c /tmp/ccaossic.ltrans0.ltrans.o
表示链接器找到了大小为 28 字节的 .text.port_lock
部分
在输入文件 /tmp/ccaossic.ltrans0.ltrans.o
并将其映射到输出 .text
部分中的地址 0x000012a8。同样的
第二次出现:
.text.port_lock
0x00001f70 0x1c /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chsys.o)
表示在输入中也找到了具有相同名称和大小的输入节
文件/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chsys.o)
并映射到输出 .text
部分中的地址 0x00001f70。
总共有.text.port_lock
输入部分,全部为28字节,
映射到这些输入文件的输出 .text
部分:
/tmp/ccaossic.ltrans0.ltrans.o
/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chsys.o)
/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chthreads.o)
/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chcore_v7m.o)
/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chmemcore.o)
/home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chschd.o)
在所有 6 种情况中,输入部分不包含任何符号,特别是 没有功能。作为对比,下面是一个确实包含符号的输入部分的示例:
.text 0x000002f0 0x28 /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chcoreasm_v7m.o)
0x000002f0 _port_switch
0x00000300 _port_thread_start
0x00000310 _port_switch_from_isr
0x00000314 _port_exit_from_isr
这是来自 /home/fotis/Documents/Resources/Chibios/Chibios/Debug/libChibios.a(chcoreasm_v7m.o)
的输入 .text
部分。
映射文件不包含 port_lock
函数被多次链接的指示。它不包含
表明该函数已链接。如果它被链接多次那么就有
将是一个多重定义链接错误(除非它有
被注释为 weak symbol )。
为什么这六个不包含符号的 28 字节输入部分全部链接在一起,或者它们是否
我没有足够的证据或 ChibiOS 专业知识。我注意到
这些输入部分来自的所有目标文件(除了其中一个)都是
libChibios
的存档成员。有鉴于此,值得记住的是,如果您的链接
出于任何原因需要存档成员,那么默认情况下您将链接整个
存档成员,即使它包含的内容比您需要的更多。另一方面,事实
一些port_lock
输入部分被丢弃,一些被保留表明有
是需要保留那些被保留的东西。如果出于我自己狡猾的原因我编写了一个源文件
本质上就像:
static int __attribute__((section(".text.foo"))) __attribute__((used))
boo(int i)
{
return i * 2;
}
int bar(int i)
{
return boo(i);
}
然后在我的 map 文件中,您将看到一个名为 .text.foo
的空输入部分。这
不会告诉您有关我链接的符号的任何信息。
How can I tell the toolchain to only link once each function?
链接器不会多次链接任何符号定义,特殊情况除外 弱符号的情况。您的映射文件不包含任何函数被多次链接的证据。
How can I reduce the final file size?
当然,使用 -Os
编译您的版本。并尽量减少链接冗余,
请参阅this question .
关于c - 了解 map 文件,优化大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36667991/