【问题标题】:why my executable is bigger after linking为什么链接后我的可执行文件更大
【发布时间】:2016-08-26 18:08:48
【问题描述】:

我有一个需要在不同芯片上运行的小型 C 程序。 可执行文件应小于 32kb。 为此,我有几个工具链,其中包含用于 arm、mips 等的不同编译器。

该程序由几个文件组成,每个文件都被编译成一个目标文件,然后链接在一起成为一个可执行文件。

当我使用系统 gcc (x86) 时,我的可执行文件有 15kb 大。 使用 arm 工具链,可执行文件大小为 65kb。 使用另一个工具链是 47kb。

例如,对于 arm,可执行文件中包含的所有对象加起来都是 14kb 大。

使用以下选项编译对象:

-march=armv7-m -mtune=cortex-m3 -mthumb -msoft-float -Os

使用以下选项进行链接:

-s -specs=nosys.specs -march-armv7-m

nosys.specs 库大小为 274 字节。

当我的代码只有 14kb 而库是 274 字节时,为什么我的可执行文件仍然大得多(65kb)?

更新:

根据答案的建议,我从我的代码中删除了所有 malloc 和 printf 命令,并删除了未使用的包含。我还添加了编译标志 -ffunction-sections -fdata-sections 和链接标志 --gc-sections ,但可执行文件仍然太大。

为了进行实验,我创建了一个虚拟程序:

int main()
{
    return 1;
}

当我使用不同的编译器编译程序时,我会得到非常不同的可执行文件大小:

8.3 KB : gcc -Os
22 KB  : r2-gcc -Os
40 KB  : arm-gcc --specs=nosys.specs -Os
1.1 KB : avr-gcc -Os

那么为什么我的 arm-gcc 可执行文件要大得多? 我猜 avr-gcc 可执行文件也会进行静态链接。

【问题讨论】:

  • 首先这是什么文件格式,它是原始二进制图像还是像 elf、coff 或 exe 之类的?几乎所有格式的文件大小不一定是重要的实际二进制文件的直接指标。对于 x86 与 arm,可能有一些动态库与静态库。
  • 也许从查看您的链接器映射文件输出开始 - 这应该让您了解链接到图像中的内容并占用所有内存。我可以推测,但这只是——推测......
  • 您的 x86 版本是否托管?即它是为在完整的 GPOS(如 WINdows 或 Linux)上运行而构建的吗?独立应用程序必须将其所有 I/O 和库代码静态链接,而 GPOS 将支持到标准库和操作系统库的动态链接,并且大部分 I/O 功能将由操作系统提供。
  • x86 构建确实是托管的,其他编译器进行静态链接(我猜)。但是例如为什么我的 amtel 芯片(avr-gcc 编译器)的 exec 比 arm-gcc 小得多?

标签: c arm embedded


【解决方案1】:

您的 x86 可执行文件可能是动态链接的,因此您使用的任何标准库函数(mallocprintf、字符串和数学函数等)都不包含在二进制文件中。

ARM 可执行文件是静态链接的,因此这些函数必须包含在您的二进制文件中。这就是它更大的原因。为了使其更小,您可能需要考虑使用 -ffunction-sections -fdata-sections 进行编译,然后与 --gc-sections 链接以丢弃二进制文件中任何未使用的函数或数据。

(“nosys.specs 库”不是库。它是一个配置文件。真正的库文件在别处。)

【讨论】:

  • 注意--gc-sections(两个连字符)或-Wl,--gc-sections是通过gcc的方式传递给链接器的
  • 感谢您的提示。不幸的是,在我的情况下,这些标志不会减少 exec 的大小。
【解决方案2】:

嵌入式软件移植取决于目标硬件和软件平台。 硬件平台分为可以运行linux os的mcu、cpus。 软件平台包括编译工具链和库。

mcu和x86硬件平台比较程序镜像大小没有意义。 但值得在相同类型的 CPU 上使用不同的工具链比较程序映像大小。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多