Linux C程序的连接 与 未用代码

写代码的过程不免会出现存在未用代码的状况 (通常是未用到的函数)
尤为在基础组件的编码过程当中(有些函数不会被调用)
如何让生成的二进制可执行文件不包含冗余信息呢?

状况是这样的,有一个基础组件,有六组函数,文件就一个 xxx.h 和 xxx.c
而后编译成 xxx.o   (gcc -c xxx.c

(37K 的 xxx.o)
函数

而后主程序用到其中的一组函数,因而须要include xxx.h
而且连接时须要连接到xxx.o     (gcc -o main main.c xxx.o 编译连接一块儿了)

(44K 的 main,实际只用了组件的很小一部分)
工具

后来发现main程序(二进制可执行文件)特别大,由于这个程序包含了所有六组的函数的代码
可使用nm命令来查看 能够清楚的看到所有函数都被连接进去了
(nm用来列出目标文件的符号清单)

(箭头指向的才是使了的函数,这个图有误,但无关痛痒)

原来gcc会直接连接整个部分而无论你使用与否
使用 readelf查看生成的 xxx.o文件里面的 section(段)信息

所有函数和数据之类都是放到一个段(section)的

而连接操做以section做为最小的处理单元,只要一个section中有某个符号被引用,该section就会被放入output中。因而所有代码都被编译到了main中。

怎样解决这个问题呢?查阅了gcc的文档后
发现有两个参数可使用
一个是 -ffunction-sections (为每一个function函数分配独立的section)
另外一个是 -fdata-sections (为每一个data item数据项分配独立的section)

如今使用 gcc -c -ffunction-sections -fdata-sections xxx.c 编译

(xxx.o的文件尺寸明显变大了,由于段多了)

性能

此时再查看 section信息

段已经多得显示不全了(除了接口函数外,还有一系列内部函数)

而后连接的时候使用 -Wl,--gc-sections
-Wl,的意思是将后面的内容传递给连接器
--gc-sections是连接器参数,不连接未使用的section

如今使用 gcc -Wl,--gc-sections -o main main.c xxx.o 来编译&连接
编码


如今main的大小已经明显变小了(44K -> 18K)

再用 nm命令查看

原来的符号表已经少了不少了(清除了无用的)

既然能够这样,为啥默认不采用这种方式呢?
有人说每一个函数分个段,程序执行的时候段间跳转,多慢啊
应该不会的,可使用readelf读取main的信息

能够清楚的看到并无不少的(冗余)段,代码主体仍是在一块儿的

至于这个参数, gcc的 官方文档以下

大概意思就是:在目标文件中每一个函数、数据项使用独立的段,段名由函数、数据项名决定。使用这个选项能够提升指令空间的利用率。大多数使用ELF目标文件格式和SPARC处理器运行Solaris2有连接器支持它。AIX未来可能支持。当你使用这个时,汇编器和连接器会产生更大的目标文件,而且处理得更慢。你也不能使用gprof(一个性能分析工具)在你用了这个选项后,并且若是同时用了-g选项,调试的时候可能会产生问题。

官方文档就只说明了这些,至于有没有其余的潜在问题,还得看gcc实现了吧。

在 Release版本中,使用这个仍是有明显的好处的。 spa

相关文章
相关标签/搜索