DS5编译器优化未使用函数

嵌入式开发中硬件资源非常宝贵,当工程中包含大量的未调用函数时,生成的二进制文件的体积会增大,浪费宝贵的存储资源。手动统计和删除未调用函数很不方便,有的平台代码可能以后会用到,删除也不合适。

DS-5是ARM架构处理器常用的开发平台,包括编辑器、编译器、调试器等一全套开发工具。DS-5编译器提供相关的选项可以自动统计未调用的函数,并且能够在不删除代码的情况下,自动忽略对应的代码段,不链接到最终的目标文件中,减小二进制文件的体积。过程如下:

  1. 编译源代码
  2. 使用链接选项--feedback=filename,生成一个反馈文件,记录未使用的函数
  3. 使用编译选项--feedback=filename,将文件反馈给编译器

编译器会根据链接器生成的反馈文件来编译源代码,链接器随后会丢弃这些未调用的函数,最终的可执行文件不会包含这些代码。

下面通过示例来描述这个过程。某个简单的工程包含如下3个文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/* file main.c */
#include <stdio.h>
#include "util.h"

int main()
{
int a = 3, b = 4;
int c = sum(a, b);
/* inc()没有被调用 */
}

/* file util.c */
#include "util.h"

int sum(int a, int b)
{
return a + b;
}

int inc(int n)
{
return n + 1;
}

/* file util.h */
#ifndef __UTIL_H_
#define __UTIL_H_

int sum(int, int);
int inc(int);

#endif

为了实现上述过程,要将编译和链接过程分开写,并且都加上--feedback选项。项目的Makefile如下:

1
2
3
4
5
6
main.o: main.c
armcc -c --feedback=unused.txt main.c -o main.o
util.o: util.c
armcc -c --feedback=unused.txt util.c -o util.o
test: main.o util.o
armlink --feedback=unused.txt util.o main.o -o test.axf

第一次构建,编译器会有告警,提示unused.txt文件不存在。构建完成后,会生成一个unused.txt文件,文件内容如下:

1
2
3
4
5
;#<FEEDBACK># ARM Linker, 5050041: Last Updated: Tue Jul 04 09:06:38 2017
;VERSION 0.2
;FILE main.o
;FILE util.o
inc <= USED 0

文件中记录inc函数使用的次数为0,之后的每一次构建,编译器和链接器都会根据此文件,忽略未调用的函数。如果代码有变更,函数的使用情况有变化,需要将unused.txt删除,重新生成一次。

对比没有加上--feedback选项的版本生成的二进制文件,文件尺寸会减小。在我工作的项目中,使用该方法将可执行文件体积减小了约10%,优化效果还是相当可观的。

参考

  1. Eliminating unused functions