gcc 编译选项

本文介绍了GCC编译器的不同优化级别及特定选项,如-Os、-O2、-O3等,以及如何通过-ffunction-sections和-fdata-sections结合-Wl,--gc-sections来移除未使用的函数和数据,减少最终可执行文件的体积。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原来-Os相当于-O2.5。是使用了所有-O2的优化选项,但又不缩减代码尺寸的方法。

-ffunction-sections
       -fdata-sections
           Place each function or data item into its own section in the output
           file if the target supports arbitrary sections.  The name of the
           function or the name of the data item determines the section's name
           in the output file.

           Use these options on systems where the linker can perform
           optimizations to improve locality of reference in the instruction
           space.  Most systems using the ELF object format and SPARC
           processors running Solaris 2 have linkers with such optimizations.
           AIX may have these optimizations in the future.

           Only use these options when there are significant benefits from
           doing so.  When you specify these options, the assembler and linker
           will create larger object and executable files and will also be
           slower.  You will not be able to use "gprof" on all systems if you
           specify this option and you may have problems with debugging if you
           specify both this option and -g.

1、-pedantic 选项,那么使用了扩展语法的地方将产生相应的警告信息

2、-Wall 使用它能够使GCC产生尽可能多的警告信息

3、-Werror,它要求GCC将所有的警告当成错误进行处理

-ffunction-sections, -fdata-sections会使compiler为每个function和data item分配独立的section。 --gc-sections会使ld删除没有被使用的section。

链接操作以section作为最小的处理单元,只要一个section中有某个符号被引用,该section就会被放入output中。

这些选项一起使用会从最终的输出文件中删除所有未被使用的function和data, 只包含用到的unction和data。






写代码的过程难免会出现存在未用代码的情况 (一般是未用到的函数)

尤其在基础 组件的编码过程中(有些函数不会被调用)
如何让生成的二进制可执行文件不包含 冗余信息呢?


原来gcc会直接链接整个部分而不管你使用与否


链接操作以section作为 最小的处理单元,只要一个section中有某个符号被引用,该section就会被放入output中。于是全部代码都被编译到了main中。

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



文件尺寸明显变大了,因为段多了


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

至于这个参数,gcc的 官方文档如下
Linux <wbr>C程序的链接 <wbr>与 <wbr>未用代码
大概意思就是:在目标文件中每个函数、数据项使用独立的段,段名由函数、数据项名决定。使用这个选项可以提高指令空间的利用率。大多数使用ELF目标文件格式和SPARC处理器运行Solaris2有链接器支持它。AIX将来可能支持。当你使用这个时,汇编器和链接器会产生更大的目标文件,并且处理得更慢。你也不能使用gprof(一个性能分析工具)在你用了这个选项后,而且如果同时用了-g选项,调试的时候可能会产生问题。

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

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



每个级别都有不同的目标:
1)-O(O0) 默认选项,也可显式声明 不做任何优化
2)-O1    尽量不增加编译时间的前提下,生成优化后的程序。在编译时间和优化之间进行了折中。
3)-O2    涵盖-O1的优化选项,在空间和时间之间进行了折中,尽量在少增加空间的前提下,进行了优化(loop unrolling and function inlining 都没有涵盖)
4)-Os    与O2类似,但更强调空间,去掉了-O2中有关对齐的选项,节省空间
5)-O3    与空间相比,更强调性能,在-O2的基础上增加了部分优化  但效果一般,使用较少(可能空间过大,引起cache命中率下降,导致性能下降)







objcopy选项-S

--strip-all 去掉源文件的符号信息和relocation信息

objcopy用于将object的部分获全部内容拷贝到另一个object,从而可以实现格式的变换。

objcopy可用用于将文件转换成S-record格式或者raw二进制格式。

例如,

         xxxx-elf-objcopy –O srec test.o test.s19

则将test.o转换成s-record文件中。通常涉及到text段。

         xxxx-elf-objcopy –O binary test.o test.bin

则将test.o转换成raw binary文件格式。

        当将 object 文件转换成 raw binary 格式时,通常将去除掉 symbols relocation 信息。在生成 s-record 过程中,有时需要用选项 “-S” “-R” 去除掉 binary 文件, s-record 文件不需要的相应信息。



uboot源代码的tools/目录下有mkimage工具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件。

mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字节的头,记录参数所指定的信息,这样uboot才能识别这个映象是针对哪个CPU体系结构的,哪个OS的,哪种类型,加载内存中的哪个位置, 入口点在内存的那个位置以及映象名是什么




uboot源代码的tools/目录下有mkimage工具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件。

mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字节的头,记录参数所指定的信息,这样uboot才能识别这个映象是针对哪个CPU体系结构的,哪个OS的,哪种类型,加载内存中的哪个位置, 入口点在内存的那个位置以及映象名是什么

参数说明:

-A 指定CPU的体系结构:
--------------------------------------------------------------
取值 表示的体系结构
alpha Alpha
arm A RM
x86 Intel x86
ia64 IA64
mips MIPS
mips64 MIPS 64 Bit
ppc PowerPC
s390 IBM S390
sh SuperH
sparc SPARC
sparc64 SPARC 64 Bit
m68k MC68000



-O 指定操作系统类型,可以取以下值:
--------------------------------------------------------------
openbsd、netbsd、freebsd、4_4bsd、linux、svr4、esix、solaris、irix、sco、dell、ncr、lynxos、vxworks、psos、qnx、u-boot、rtems、artos



-T 指定映象类型,可以取以下值:
--------------------------------------------------------------
standalone、kernel、ramdisk、multi、firmware、script、filesystem



-C 指定映象压缩方式,可以取以下值:
--------------------------------------------------------------
none 不压缩
gzip 用gzip的压缩方式
bzip2 用bzip2的压缩方式



-a 指定映象在内存中的加载地址,映象下载到内存中时,要按照用mkimage制作映象时,这个参数所指定的地址值来下载


-e 指定映象运行的入口点地址,这个地址就是-a参数指定的值加上0x40(因为前面有个mkimage添加的0x40个字节的头)

-n 指定映象名

-d 指定制作映象的源文件




objdump命令是Linux下的反汇编目标文件或者可执行文件的命令,它还有其他作用,下面以ELF格式可执行文件test为例详细介绍:


objdump -f test

显示test的文件头信息


objdump -d test

反汇编test中的需要执行指令的那些section



objdump -D test

与-d类似,但反汇编test中的所有section



objdump -h test

显示test的Section Header信息



objdump -x test

显示test的全部Header信息




objdump -s test

除了显示test的全部Header信息,还显示他们对应的十六进制文件代码




举例:

将C源代码和反汇编出来的指令对照:

1.

编译成目标文件(要加-g选项)

gcc -g -o test.c


2.

输出C源代码和反汇编出来的指令对照的格式

objdump -S test.o

如下:






如何对任意一个二进制文件进行反汇编?

我们可以这样做:

objdump -D -b binary -m i386 a.bin

-D表示对全部文件进行反汇编,-b表示二进制,-m表示指令集架构,a.bin就是我们要反汇编的二进制文件


objdump -m可以查看更多支持的指令集架构,如i386:x86-64,i8086等


另外上面的所有objdump命令的参数同样适用于arm-linux-objdump。


同时我们也可以指定big-endian或little-endian(-EB或-EL),我们可以指定从某一个位置开始反汇编等。所以objdump命令是非常强大的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值