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版本中,使用这个还是有明显的好处的。

转载于:https://my.oschina.net/chishaxie/blog/85459

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值