转自:http://blog.csdn.net/princess9/article/details/6567678html
通常来讲要现有项目中的编译选项,设置新的project的编译选项linux
编译器 就是将“高级语言”翻译为“机器语言(低级语言)”的程序。一个现代编译器的主要工做流程:源代码 (source code) → 预处理器 (preprocessor) → 编译器 (compiler) → 汇编程序 (assembler) → 目标代码 (object code) → 连接器 (Linker) → 可执行程序 (executables)。c++
分类
GCC家族
Cygwin Mingw32 DJGPP Dev-C++ (Mingw32) 还有正宗的GNU GCC 2.95.5~3.0.0.4版本 GNU C++ g++ 是一个开源的C++编译器,GCC3.3对标准化C++的支持达96.15%。 值得一提的是,gcc是gnu c的编译器, g++是gnu c++的编译器, 而egcs(Enhanced GNU Compiler Suite)能够认为是gcc的改进版。目前gcc已经更名,从原来表明GNU C Compiler改变为表明GNU Compiler Collection。而MinGW或Cgywin,是在windows平台上的gnu c/c++编译器,以及库文件,运行环境的集合。 在GCC家族中GNU GCC是根本,其它的编译器版本都是从它导出的。其中,Cygwin和Mingw32都是WIN32平台下的编译器,DJGPP是DOS下的32位编译 器。你们所熟知的DEV-C++充其量只是GCC的一个外壳,它所自带的编译器就是Mingw32的一个版本。这些GCC的版本中,Cygwin是最大 的,它与其说是一个编译器,倒不如说是一套编程工具。它不只有编译器,还有其它不少的工具。其实,它就是一个UNIX系统在WIN32平台上的实现。实现 了大多经常使用的UNIX工具,最近的版本中连Apache这样的“工具”都集成进来的。不过,Cygwin虽然功能强大,但它却不是很易用(和UNIX相 似,熟悉UNIX的人用它能够很快上手),由于太多其它的工具分散了人们的注意力。相比之下Mingw32就要好用得多,它只有最基本的几个编程工具(只 惋惜它不自带GDB)。GCC中并不仅是C/C++编译器,其中还有不少其它的编译器如JAVA,Fortran,ADA等。它是一个编译器集合,不过有 些编译器只能在UNIX系统上用。web
MS家族
MSC 5.0、6.0、7.0 MSQC 1.0、2.5 MSVC 1.0、4.二、6.0、7.0 Visual C++ VC++6.0对标准化C++的兼容仅达83.43%。 它是Visual Studio、Visual Studio.net 200二、Visual Studio.net 200三、Visual Studio.net 2005的后台 C++编译器。随着Stanley Lippman等编译器设计大师的加盟,它变得很是成熟可靠了。Visual C++ 7.1对标准C++的兼容性达到98.22%。objective-c
Linux中gcc,g++经常使用编译选项
-x language filename
设定文件所使用的语言,使后缀名无效,对之后的多个有效.也就是根据约定,C语言的后缀名称是.c的,而C++的后缀名是.C或者.cpp,若是你很个 性,决定你的C代码文件的后缀名是.pig 哈哈,那你就要用这个参数,这个参数对他后面的文件名都起做用,除非到了下一个参数的使用。创意产品网 可使用的参数有下面的这些:
`c', `objective-c', `c-header', `c++', `cpp-output', `assembler', and `a
ssembler-with-cpp'.
看到英文,应该能够理解的。
例子用法: cd..
gcc -x c hello.pig数据库
-x none filename
关掉上一个 选项 ,也就是让gcc根据文件名后缀,自动识别文件类型
例子用法:
gcc -x c hello.pig -x none hello2.c
-c
只激活预处理,编译,和汇编,也就是他只把程序作成obj文件
例子用法:
gcc -c hello.c
他将生成.o的obj文件
-S
只激活预处理和编译,就是指把文件编译成为汇编代码。
例子用法
gcc -S hello.c
他将生成.s的汇编代码,你能够用文本编辑器察看
-E
只激活预处理,这个不生成文件,你须要把它重定向到一个输出文件里面.
例子用法:
gcc -E hello.c > pianoapan.txt
gcc -E hello.c | more
慢慢看吧,一个hello word 也要预处理成800行的代码
-o
制定目标名称,缺省的时候,gcc 编译出来的文件是a.out,很难听,若是你和我有同感,改掉它,哈哈
例子用法
gcc -o hello.exe hello.c (哦,windows用习惯了)
gcc -o hello.asm -S hello.c
-pipe
使用管道代替编译中临时文件,在使用非gnu汇编工具的时候,可能有些问题
gcc -pipe -o hello.exe hello.c 编程
-shared-libgcc 该选项指定使用共享版本的libgcc,在没有共享版本的libgcc的机器上该选项无效windows
-static-libgcc数组
-specs=<filename> gcc驱动程序读取该文件以肯定哪些选项应该传递给那些子进程。
该选项能够经过指定配置文件来覆盖默认配置,指定的文件将在默认配置文件读取后进行处理以修改默认配置。sass
-ansi
关闭gnu c中与ansi c不兼容的特性,激活ansi c的专有特性(包括禁止一些asm inline typeof关键字,以及UNIX,vax等预处理宏
/* 注释中的不经常使用****************************************************
-fno-asm
此选项 实现ansi 选项 的功能的一部分,它禁止将asm,inline和typeof用做关键字。
-fno-strict-prototype
只对g++ 起做用,使用这个 选项 ,g++ 将对不带参数的函数,都认为是没有显式的对参数的个数和类型说明,而不是没有参数.
而gcc不管是否使用这个参数,都将对没有带参数的函数,认为没有显式说明的类型
-fthis-is-varialble
就是向传统c++看齐,可使用this当通常变量使用.
-fcond-mismatch
容许条件表达式的第二和第三参数类型不匹配,表达式的值将为void类型
-funsigned-char
-fno-signed-char
-fsigned-char
-fno-unsigned-char
这四个参数是对char类型进行设置,决定将char类型设置成unsigned char(前两个参
数)或者 signed char(后两个参数)
*注释完成*********************************************/
-include file
包含某个代码,简单来讲,就是便于某个文件须要另外一个文件的时候,就能够用它设
定,功能就至关于在代码中使用#i nclude<filename>
例子用法:
gcc hello.c -include /root/pianopan.h
-imacros file
将file文件的宏,扩展到gcc/g++ 的输入文件,宏定义自己并不出如今输入文件中
-Dmacro
至关于C语言中的#define macro
-Dmacro=defn
至关于C语言中的#define macro=defn
-Umacro
至关于C语言中的#undef macro
-undef
取消对任何非标准宏的定义
-Idir
在你是用#i nclude"file"的时候,gcc/g++ 会先在当前目录查找你所制定的头文件,如
果没有找到,他回到缺省的头文件目录找,若是使用-I制定了目录,他
回先在你所制定的目录查找,而后再按常规的顺序去找.
对于#i nclude<file>,gcc/g++ 会到-I制定的目录查找,查找不到,而后将到系统的缺
省的头文件目录查找
-I-
就是取消前一个参数的功能,因此通常在-Idir以后使用
-idirafter dir
在-I的目录里面查找失败,讲到这个目录里面查找.
-iprefix prefix
-iwithprefix dir
通常一块儿使用,当-I的目录查找失败,会到prefix+dir下查找
-nostdinc
使编译器再也不系统缺省的头文件目录里面找头文件,通常和-I联合使用,明确限定头
文件的位置
-nostdin C++
规定不在g++ 指定的标准路经中搜索,但仍在其余路径中搜索,.此选项 在创libg++库
使用
-C
在预处理的时候,不删除注释信息,通常和-E使用,有时候分析程序,用这个很方便的
-M
生成文件关联的信息。包含目标文件所依赖的全部源代码你能够用gcc -M hello.c
来测试一下,很简单。
-MM
和上面的那个同样,可是它将忽略由#i nclude<file>形成的依赖关系。
-MD
和-M相同,可是输出将导入到.d的文件里面
-MMD
和-MM相同,可是输出将导入到.d的文件里面
-Wa,option
此选项 传递option给汇编程序;若是option中间有逗号,就将option分红多个选项 ,然
后传递给会汇编程序
-Wl.option
此选项 传递option给链接程序;若是option中间有逗号,就将option分红多个选项 ,然
后传递给会链接程序.
-llibrary
制定编译的时候使用的库
例子用法
gcc -lcurses hello.c
使用ncurses库编译程序
-Ldir
制定编译的时候,搜索库的路径。好比你本身的库,能够用它制定目录,否则
编译器将只在标准库的目录找。这个dir就是目录的名称。
-O0
-O1
-O2
-O3
编译器的优化选项 的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
-g
只是编译器,在编译的时候,产生调试信息。
-gstabs
此选项 以stabs格式声称调试信息,可是不包括gdb调试信息.
-gstabs+
此选项 以stabs格式声称调试信息,而且包含仅供gdb使用的额外调试信息.
-ggdb
此选项 将尽量的生成gdb的可使用的调试信息.
-static
此选项 将禁止使用动态库,因此,编译出来的东西,通常都很大,也不须要什么
动态链接库,就能够运行.
-share
此选项 将尽可能使用动态库,因此生成文件比较小,可是须要系统由动态库.
-traditional
试图让编译器支持传统的C语言特性
-
-v
-
打印详细的编译连接过程,
本文讨论gcc的一些经常使用编译选项对代码的影响。固然代码变了,
它的内存布局也就会变了,随之exploit也就要作相应的变更。
gcc的编译选项实在太多,本文检了几个最经常使用的选项。
★ 演示程序
[alert7@redhat62 alert7]$ cat > test.c
#include <stdio.h>
void hi(void)
{
printf("hi");
}
int main(int argc, char *argv[])
{
hi();
return 0;
}
★ 通常状况
[alert7@redhat62 alert7]$ gcc -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11773 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483e4 <main>: push %ebp
0x80483e5 <main+1>: mov %esp,%ebp
0x80483e7 <main+3>: call 0x80483d0 <hi>
0x80483ec <main+8>: xor %eax,%eax
0x80483ee <main+10>: jmp 0x80483f0 <main+12>
0x80483f0 <main+12>: leave
0x80483f1 <main+13>: ret
....
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483d0 <hi>: push %ebp
0x80483d1 <hi+1>: mov %esp,%ebp
0x80483d3 <hi+3>: push $0x8048450
0x80483d8 <hi+8>: call 0x8048308 <printf>
0x80483dd <hi+13>: add $0x4,%esp
0x80483e0 <hi+16>: leave
0x80483e1 <hi+17>: ret
0x80483e2 <hi+18>: mov %esi,%esi
End of assembler dump.
来看看部分的内存映象
(内存高址)
+--------+
|bffffbc4| argv的地址(即argv[0]的地址)
0xbffffb84 +--------+
|00000001| argc的值
0xbffffb80 +--------+
|400309cb|main的返回地址
0xbffffb7c +--------+ <-- 调用main函数前的esp
|bffffb98| 调用main函数前的ebp
0xbffffb78 +--------+ <-- main函数的ebp
|080483ec| hi()的返回地址
0xbffffb74 +--------+
|bffffb78| 调用hi()前的esp
0xbffffb70 +--------+
|08048450| "hi"的地址
0xbffffb6c +--------+
| ...... |
(内存低址)
leave 指令所作的操做至关于MOV ESP,EBP 而后 POP EBP
ret 指令所作的操做至关于POP EIP
★ -O 编译选项
With `-O', the compiler tries to reduce code size and execution time.
When you specify `-O', the two options `-fthread-jumps' and
`-fdefer-pop' are turned on
优化,减小代码大小和执行的时间
[alert7@redhat62 alert7]$ gcc -O -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11757 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483d8 <main>: push %ebp
0x80483d9 <main+1>: mov %esp,%ebp
0x80483db <main+3>: call 0x80483c8 <hi>
0x80483e0 <main+8>: xor %eax,%eax
0x80483e2 <main+10>: leave
0x80483e3 <main+11>: ret
0x80483e4 <main+12>: nop
...
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483c8 <hi>: push %ebp
0x80483c9 <hi+1>: mov %esp,%ebp
0x80483cb <hi+3>: push $0x8048440
0x80483d0 <hi+8>: call 0x8048308 <printf>
0x80483d5 <hi+13>: leave
0x80483d6 <hi+14>: ret
0x80483d7 <hi+15>: nop
End of assembler dump.
在main()中,把一条jmp指令优化掉了,很显然,这条指令是能够不须要的。
在hi()中,把add $0x4,%esp优化掉了,这会不会使stack不平衡呢?
来看看部分的内存映象
(内存高址)
+--------+
|bffffbc4| argv的地址(即argv[0]的地址)
0xbffffb84 +--------+
|00000001| argc的值
0xbffffb80 +--------+
|400309cb|main的返回地址
0xbffffb7c +--------+ <-- 调用main函数前的esp
|bffffb98| 调用main函数前的ebp
0xbffffb78 +--------+ <-- main函数的ebp
|080483e0| hi()的返回地址
0xbffffb74 +--------+
|bffffb78| 调用hi()前的esp
0xbffffb70 +--------+
|08048440| "hi"的地址
0xbffffb6c +--------+
| ...... |
(内存低址)
leave 指令所作的操做至关于把MOV ESP,EBP 而后 POP EBP
看到leave指令操做了没有,先把ebp-->esp,再pop ebp,这样即便
在过程内堆栈的esp,ebp是不平衡的,但只要返回时候碰到leave指令
就会平衡了,因此把add $0x4,%esp优化掉也是没有问题的。
★ -O2 编译选项
-O2 Optimize even more. Nearly all supported optimizations that do
not involve a space-speed tradeoff are performed. Loop unrolling
and function inlining are not done, for example. As compared to -O,
this option increases both compilation time and the performance of
the generated code.
[alert7@redhat62 alert7]$ gcc -O2 -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11757 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483d8 <main>: push %ebp
0x80483d9 <main+1>: mov %esp,%ebp
0x80483db <main+3>: call 0x80483c8 <hi>
0x80483e0 <main+8>: xor %eax,%eax
0x80483e2 <main+10>: leave
0x80483e3 <main+11>: ret
...
0x80483ef <main+23>: nop
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483c8 <hi>: push %ebp
0x80483c9 <hi+1>: mov %esp,%ebp
0x80483cb <hi+3>: push $0x8048440
0x80483d0 <hi+8>: call 0x8048308 <printf>
0x80483d5 <hi+13>: leave
0x80483d6 <hi+14>: ret
0x80483d7 <hi+15>: nop
End of assembler dump.
因为程序比较简单,再优化也没有好优化的了,因此跟-O出来的同样。
★ -fomit-frame-pointer 编译选项
-fomit-frame-pointer
Don't keep the frame pointer in a register for functions
that don't need one. This avoids the instructions to save,
set up and restore frame pointers; it also makes an extra
register available in many functions. It also makes
debugging impossible on most machines.
忽略帧指针。这样在程序就不须要保存,安装,和恢复ebp了。这样ebp也就是一个
free的register了,在函数中就能够随便使用了。
[alert7@redhat62 alert7]$ gcc -fomit-frame-pointer -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11773 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483e0 <main>: call 0x80483d0 <hi>
0x80483e5 <main+5>: xor %eax,%eax
0x80483e7 <main+7>: jmp 0x80483f0 <main+16>
0x80483e9 <main+9>: lea 0x0(%esi,1),%esi
0x80483f0 <main+16>: ret
....
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483d0 <hi>: push $0x8048450
0x80483d5 <hi+5>: call 0x8048308 <printf>
0x80483da <hi+10>: add $0x4,%esp
0x80483dd <hi+13>: ret
0x80483de <hi+14>: mov %esi,%esi
End of assembler dump.
在main()和hi()中都去掉了如下指令
push %ebp
mov %esp,%ebp//这两条指令安装
leave//这条指令恢复
来看看部分的内存映象
(内存高址)
+--------+
|bffffbc4| argv的地址(即argv[0]的地址)
0xbffffb84 +--------+
|00000001| argc的值
0xbffffb80 +--------+
|400309cb|main的返回地址
0xbffffb7c +--------+
|080483e5| hi()的返回地址
0xbffffb78 +--------+
|08048450| "hi"字符串的地址
0xbffffb74 +--------+
| ...... |
(内存低址)
没有保存上层执行环境的ebp.
★ -fomit-frame-pointer && -O2
-fomit-frame-pointer编译选项去掉了
push %ebp
mov %esp,%ebp//这两条指令安装
leave//这条指令恢复
-O2编译选项去掉了
add $0x4,%esp
两个加起来会不会这四条指令一块儿去掉,从而使stack不平衡呢?
[alert7@redhat62 alert7]$ gcc -fomit-frame-pointer -O2 -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11741 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483d8 <main>: call 0x80483c8 <hi>
0x80483dd <main+5>: xor %eax,%eax
0x80483df <main+7>: ret
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483c8 <hi>: push $0x8048430
0x80483cd <hi+5>: call 0x8048308 <printf>
0x80483d2 <hi+10>: add $0x4,%esp
0x80483d5 <hi+13>: ret
0x80483d6 <hi+14>: mov %esi,%esi
End of assembler dump.
来看看部分的内存映象
(内存高址)
+--------+
|bffffbc4| argv的地址(即argv[0]的地址)
0xbffffb84 +--------+
|00000001| argc的值
0xbffffb80 +--------+
|400309cb|main的返回地址
0xbffffb7c +--------+
|080483dd| hi()的返回地址
0xbffffb78 +--------+
|08048430| "hi"字符串的地址
0xbffffb74 +--------+
| ...... |
(内存低址)
此时就没有把add $0x4,%esp优化掉,若是优化掉的话,整个stack就
会变的不平衡,从而会致使程序出错。
★ -fPIC 编译选项
-fPIC If supported for the target machine, emit position-independent
code, suitable for dynamic linking,even if branches need large
displacements.
产生位置无关代码(PIC),通常建立共享库时用到。
在x86上,PIC的代码的符号引用都是经过ebx进行操做的。
[alert7@redhat62 alert7]$ gcc -fPIC -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11805 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483f8 <main>: push %ebp
0x80483f9 <main+1>: mov %esp,%ebp
0x80483fb <main+3>: push %ebx
0x80483fc <main+4>: call 0x8048401 <main+9>
0x8048401 <main+9>: pop %ebx//取得该指令的地址
0x8048402 <main+10>: add $0x1093,%ebx//此时ebx里面存放着是GOT表的地址
0x8048408 <main+16>: call 0x80483d0 <hi>
0x804840d <main+21>: xor %eax,%eax
0x804840f <main+23>: jmp 0x8048411 <main+25>
0x8048411 <main+25>: mov 0xfffffffc(%ebp),%ebx
0x8048414 <main+28>: leave
0x8048415 <main+29>: ret
...
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483d0 <hi>: push %ebp
0x80483d1 <hi+1>: mov %esp,%ebp
0x80483d3 <hi+3>: push %ebx
0x80483d4 <hi+4>: call 0x80483d9 <hi+9>
0x80483d9 <hi+9>: pop %ebx
0x80483da <hi+10>: add $0x10bb,%ebx
0x80483e0 <hi+16>: lea 0xffffefdc(%ebx),%edx
0x80483e6 <hi+22>: mov %edx,%eax
0x80483e8 <hi+24>: push %eax
0x80483e9 <hi+25>: call 0x8048308 <printf>
0x80483ee <hi+30>: add $0x4,%esp
0x80483f1 <hi+33>: mov 0xfffffffc(%ebp),%ebx
0x80483f4 <hi+36>: leave
0x80483f5 <hi+37>: ret
0x80483f6 <hi+38>: mov %esi,%esi
End of assembler dump.
来看看部分的内存映象
(内存高址)
+--------+
|bffffbc4| argv的地址(即argv[0]的地址)
0xbffffb84 +--------+
|00000001| argc的值
0xbffffb80 +--------+
|400309cb|main的返回地址
0xbffffb7c +--------+ <-- 调用main函数前的esp
|bffffb98| 调用main函数前的ebp
0xbffffb78 +--------+ <-- main函数的ebp
|401081ec| 保存的ebx
0xbffffb74 +--------+
|0804840d| (存放过call 0x8048401的下一条指令地址)
0xbffffb70 +--------+
|bffffb78| 调用hi()前的esp
0xbffffb6c +--------+
|08049494| GOT表地址
0xbffffb68 +--------+
|08048470|(存放过call 0x80483d9的下一条指令地址)
0xbffffb64 +--------+
| ...... |
(内存低址)
★ -static 编译选项
-static
On systems that support dynamic linking, this prevents
linking with the shared libraries. On other systems,
this option has no effect.
把一些函数都静态的编译到程序中,而无需动态连接了。
[alert7@redhat62 alert7]$ gcc -o test -static test.c
[alert7@redhat62 alert7]$ wc -c test
962808 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80481b4 <main>: push %ebp
0x80481b5 <main+1>: mov %esp,%ebp
0x80481b7 <main+3>: call 0x80481a0 <hi>
0x80481bc <main+8>: xor %eax,%eax
0x80481be <main+10>: jmp 0x80481c0 <main+12>
0x80481c0 <main+12>: leave
0x80481c1 <main+13>: ret
...
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80481a0 <hi>: push %ebp
0x80481a1 <hi+1>: mov %esp,%ebp
0x80481a3 <hi+3>: push $0x8071528
0x80481a8 <hi+8>: call 0x804865c <printf>
0x80481ad <hi+13>: add $0x4,%esp
0x80481b0 <hi+16>: leave
0x80481b1 <hi+17>: ret
0x80481b2 <hi+18>: mov %esi,%esi
End of assembler dump.
[alert7@redhat62 alert7]$ ldd test
not a dynamic executable
-static出来的代码已经没有PLT了,GOT虽然有,已经所有为0了。
★ 小节
抛砖引玉般简单的实例描述了下gcc经常使用的编译选项对代码的影响。
不正之处,还请斧正。谢谢。
不少弟兄可能都很关心如何优化编译本身的程序,虽然本人不同意"骨灰"玩法,却也不得不认可这是掌握gcc的绝佳途径;
所以献上此帖,以供各位玩家参考,绝对原创噢
============================
大多数程序和库在编译时默认的优化级别是"2"(使用gcc选项:"-O2")而且在Intel/AMD平台上默认按照i386处理器来编译。
若是你只想让编译出来的程序运行在特定的平台上,就须要执行更高级的编译器优化选项,以产生只能运行于特定平台的代码。
一种方法是修改每一个源码包中的Makefile文件,在其中寻找CFLAGS和CXXFLAGS变量(C和C++编译器的编译选项)并修改它的值。
一些源码包好比binutils, gcc, glibc等等,在每一个子文件夹中都有Makefile文件,这样修改起来就太累了!
另外一种简易作法是设置CFLAGS和CXXFLAGS环境变量。大多数configure脚本会使用这两个环境变量代替Makefile文件中的值。
可是少数configure脚本并不这样作,他们必须须要手动编辑才行。
为了设置CFLAGS和CXXFLAGS环境变量,你能够在bash中执行以下命令(也能够写进.bashrc以成为默认值):
export CFLAGS="-O3 -march=<cpu类型>" && CXXFLAGS=$CFLAGS
这是一个确保可以在几乎全部平台上都能正常工做的最小设置。
"-march"选项表示为特定的cpu类型编译二进制代码(不能在更低级别的cpu上运行),
Intel一般是:pentium2, pentium3, pentium3m, pentium4, pentium4m, pentium-m, prescott, nocona
说明:pentium3m/pentium4m是笔记本用的移动P3/P4;pentium-m是迅驰I/II代笔记本的cpu;
prescott是带SSE3的P4(以滚烫到能够煎鸡蛋而闻名);nocona则是最新的带有EMT64(64位)的P4(一样能够煎鸡蛋)
AMD一般是:k6, k6-2, k6-3, athlon, athlon-tbird, athlon-xp, athlon-mp, opteron, athlon64, athlon-fx
用AMD的通常都是DIYer,就没必要解释了吧。
若是编译时没有抱怨"segmentation fault, core dumped",那么你设定的"-O"优化参数通常就没什么问题。
不然请下降优化级别("-O3" -> "-O2" -> "-O1" -> 取消)。
我的意见:服务器使用"-O2"就能够了,它是最安全的优化参数(集合);桌面可使用"-O3" ;
不鼓励使用过多的自定义优化选项,其实他们之间没什么明显的速度差别(有时"-O3"反而更慢)。
编译器对硬件很是敏感,特别是在使用较高的优化级别的时候,一丁点的内存错误均可能致使致命的失败。
因此在编译时请千万不要超频你的电脑(我编译关键程序时老是先降频然的)。
注意:选项的顺序很重要,若是有两个选项互相冲突,则之后一个为准。
好比"-O3"将打开-finline-functions选项,可是能够用"-O3 -fno-inline-functions"既使用-O3的功能又关闭函数内嵌功能。
更多的优化选项请参见:
http://gcc.gnu.org/onlinedocs/gcc-3....e-Options.html
http://gcc.gnu.org/onlinedocs/gcc-3....4-Options.html
http://gcc.gnu.org/onlinedocs/gcc-4....e-Options.html
http://gcc.gnu.org/onlinedocs/gcc-4....4-Options.html
全部GCC选项完整列表参见:
http://gcc.gnu.org/onlinedocs/gcc-3....n-Summary.html
http://gcc.gnu.org/onlinedocs/gcc-4....n-Summary.html
有两个页面值的参考:
(对于gentoo-1.4)比较安全的优化选项
http://www.freehackers.org/gentoo/gc...flag_gcc3.html
(对于gentoo-1.4)进阶优化选项
http://www.freehackers.org/gentoo/gc...g_gcc3opt.html
*******************************************************************
哦,忘了说一声,"-O2"已经启用绝大多数安全的优化选项了,因此其实你没必要对那一堆选项发愁。
先说说"-O3"在"-O2"基础上增长的几项,你能够按需添加(还算比较安全):
[gcc-3.4.4]
-finline-functions 容许编译器选择某些简单的函数在其被调用处展开
-fweb 为每一个web结构体分配一个伪寄存器
-frename-registers 试图驱除代码中的假依赖关系,这个选项对具备大量寄存器的机器颇有效。
[gcc-4.0.2]
-finline-functions 说明如上
-funswitch-loops 将循环体中不改变值的变量移动到循环体以外
-fgcse-after-reload **不太明白它的含义**[哪位大峡知道给小弟讲解一下,先行谢过 ]
说完"-O3"再说说在嵌入式系统上经常使用的"-Os"选项,这个选项其实也很重要,它的含义是对生成的二进制代码进行尺寸上的优化,它打开了所 有"-O2"打开的选项,所以一般认为的"-Os"生成的二进制代码执行效率低的潜在乎识是错误的!固然该选项与"-O2"的不一样之处在于它在"-O2" 的基础上禁止了全部为了对齐而插入的空间,也就是将全部"-falign-*"系列的选项禁用了。这种禁用到底是否必定下降了代码的执行效率,依据程序的 不一样而不一样,听说某些状况下"-Os"的效率比"-O3"还要高14%!请兄弟们在实践中本身摸索吧...
---------------------------------------------
下面选择我认为比较重要的几项简单介绍一下[gcc-3.4.4],GCC选项完整列表太长了!精力有限。
[注意]这里列出的都是非默认 的选项,你只须要添加你所须要的选项便可
-w 禁止输出警告消息
-Werror 将全部警告转换为错误
-Wall 显示全部的警告消息
-v 显示编译程序的当前版本号
-V<version> 指定gcc将要运行的版本。只有在安装了多个版本gcc的机器上才有效。
-ansi 按照ANSI标准编译程序,但并不限制与标准并不冲突的GNU扩展(通常不用该选项)
-pedantic 若是要限制代码必须严格符合ISO标准,就在"-ansi"的基础上同时启用这个选项(不多使用)
-std=<name> 指定C语言的标准(c89,c99,gnu89),该选项禁止了GNU C的扩展关键字asm,typeof,inline (通常不用该选项)
-static 链接器将忽略动态链接库,同时经过将静态目标文件直接包含到结果目标文件完成对全部引用的解析。
-shared 链接器将生成共享目标代码,该共享库可在运行时动态链接到程序造成完整的可执行体。
若是使用gcc命令建立共享库做为其输出,该选项能够防止链接器将缺失main()方法视为错误。
为了能够正确的工做,应该一致的使用选项"-fpic"以及目标平台选项编译构成同一个库的全部共享目标模块。
-shared-libgcc 该选项指定使用共享版本的libgcc,在没有共享版本的libgcc的机器上该选项无效。
-specs=<filename> gcc驱动程序读取该文件以肯定哪些选项应该传递给那些子进程。
该选项能够经过指定配置文件来覆盖默认配置,指定的文件将在默认配置文件读取后进行处理以修改默认配置。
-pipe 使用管道而不是临时文件一个阶段到另外一个阶段交换输出的方式,能够加快编译速度。建议使用。
-o <filename> 指定输出文件,对各类输出皆有效。因为只能指定一个文件,因此在产生多个输出文件的状况下不要使用该选项。
--help 显示gcc的命令行选项列表;与"-v"一块儿使用时还将显示gcc调用的各个进程所接受的选项。
--target-help 显示目标机器相关的命令行选项列表
-b<machine> 指示须要编译程序的目标机器;默认为编译程序所运行的目标机编译代码。
目标机经过指定包含编译程序的目录来肯定,一般为/usr/local/lib/gcc-lib/<machine>/<version>
-B<lib-prefix> 指定库文件的位置,包括编译程序的文件、执行程序和数据文件,若是须要运行子程序(如cpp,as,ld)就会用该前缀来定位。
这个前缀能够是用冒号分割的多个路径,环境变量GCC_EXEC_PREFIX和这个选项有相同的效果。
-I<dir> 指定搜索系统头文件的目录,能够重复使用多个该选项指定多个目录。
-dumpmachine 显示该程序的目标机名字,不作其余任何动做
-dumpspecs 显示构件编译程序的规范信息,包括用来编译、汇编和链接gcc编译程序自身用到的全部选项,不作其余任何动做。
-dumpversion 显示编译程序自身的版本号,不作其余任何动做
-falign-functions=N 将全部函数的起始地址在N(N=1,2,4,8,16...)的边界上对齐,默认为机器自身的默认值,指定为1表示禁止对齐。
-falign-jumps=N 将分支目标在N(N=1,2,4,8,16...)的边界上对齐,默认为机器自身的默认值,指定为1表示禁止对齐。
-fno-align-labels 建议使用它,以保证不和-falign-jumps("-O2"默认启用的选项)冲突
-fno-align-loops 建议使用它,以确保不会在分支目标前插入多余的空指令。
-fbranch-probabilities 在使用"-fprofile-arcs"选项编译程序并执行它来建立包含每一个代码块执行次数的文件以后,程序能够利用这一选项再次编译,
文件中所产生的信息将被用来优化那些常常发生的分支代码。若是没有这些信息,gcc将猜想那一分支可能常常发生并进行优化。
这类优化信息将会存放在一个以源文件为名字的并以".da"为后缀的文件中。
-fno-guess-branch-probability 默认状况下gcc将使用随机模型进行猜想哪一个分支更可能被常常执行,并以此来优化代码,该选项关闭它。
-fprofile-arcs 在使用这一选项编译程序并运行它以建立包含每一个代码块的执行次数的文件后,程序能够再次使用"-fbranch-probabilities"编译,
文件中的信息能够用来优化那些常常选取的分支。若是没有这些信息,gcc将猜想哪一个分支将被常常运行以进行优化。
这类优化信息将会存放在一个以源文件为名字的并以".da"为后缀的文件中。
-fforce-addr 必须将地址复制到寄存器中才能对他们进行运算。因为所需地址一般在前面已经加载到寄存器中了,因此这个选项能够改进代码。
-fforce-mem 必须将数值复制到寄存器中才能对他们进行运算。因为所需数值一般在前面已经加载到寄存器中了,因此这个选项能够改进代码。
-ffreestanding 所编译的程序可以在独立的环境中运行,该环境能够没有标准库,并且能够不从main()函数开始运行。
该选项将设置"-fno-builtin",且等同于"-fno-hosted"。
-fhosted 所编译的程序须要运行在宿主环境中,其中须要有完整的标准库,并且main()函数具备int型的返回值。
-fno-builtin 除非利用"__builtin_"进行引用,不然不识别全部内建函数。
-fmerge-all-constants 试图将跨编译单元的全部常量值和数组合并在一个副本中。可是标准C/C++要求每一个变量都必须有不一样的存储位置。
-fmove-all-movables 将全部不变的表达式移动到循环体以外,这种作法的好坏取决于源代码中的循环结构。
-fnon-call-exceptions 产生的代码可供陷阱指令(如非法浮点运算和非法内存寻址)抛出异常,须要相关平台的运行时支持,并不广泛有效。
-fomit-frame-pointer 对于不须要栈指针的函数就不在寄存器中保存指针,所以能够忽略存储和检索地址的代码,并将寄存器用于普通用途。
全部"-O"级别都打开着一选项,但仅在调试器能够不依靠栈指针运行时才有效。建议不须要调试的状况下显式的设置它。
-fno-optional-diags 禁止输出诊断消息,C++标准并不须要这些消息。
-fpermissive 将代码中与标准不符合的诊断消息做为警告而不是错误输出。
-fpic 生成可用于共享库的位置独立代码(PIC),全部的内存寻址均经过全局偏移表(GOT)完成。该选项并不是在全部的机器上都有效。
要肯定一个地址,须要将代码自身的内存位置做为表中的一项插入。该选项能够产生在共享库中存放并从中加载的目标模块。
-fprefetch-loop-arrays 生成数组预读取指令,对于使用巨大数组的程序能够加快代码执行速度,适合数据库相关的大型软件等。
-freg-struct-return 生成用寄存器返回短结构的代码,若是寄存器没法荣纳将使用内存。
-fstack-check 为防止程序栈溢出而进行必要的检测,在多线程环境中运行时才可能须要它。
-ftime-report 编译完成后显示编译耗时的统计信息
-funroll-loops 若是在编译时能够肯定迭代的次数很是少并且循环中的指令也很是少,可使用该选项进行循环展开,以驱除循环和复制指令。
-finline-limit=<size> 对伪指令数超过<size>的函数,编译程序将不进行展开,默认为600
--param <name>=<value> gcc内部存在一些优化代码程度的限制,调整这些限制就是调整整个优化全局。下面列出了参数的名字和对应的解释:
名字 解释
max-delay-slot-insn-search 较大的数目能够生成更优化的代码,可是会下降编译速度,默认为100
max-delay-slot-live-search 较大的数目能够生成更优化的代码,可是会下降编译速度,默认为333
max-gcse-memory 执行GCSE优化使用的最大内存量,过小将使该优化没法进行,默认为50M
max-gcse-passes 执行GCSE优化的最大迭代次数,默认为1
*******************************************************************
说完了命令行选项,下面来讲说与硬件体系结构(主要是cpu)相关的设置[仅针对i386/x86_64] 最大名鼎鼎的"-march"上面已经说过了,下面讲讲别的(仅挑些实用的) -mfpmath=sse P3和athlon-tbird以上级别的cpu支持 -masm=<dialect> 使用指定的dialect输出汇编语言指令,可使用"intel"或"att";默认为"att" -mieee-fp 指定编译器使用IEEE浮点比较,这样将会正确的处理比较结果为无序的状况。 -malign-double 将double, long double, long long对齐于双字节边界上;有助于生成更高速的代码,可是程序的尺寸会变大。 -m128bit-long-double 指定long double为128位,pentium以上的cpu更喜欢这种标准。 -mregparm=N 指定用于传递整数参数的寄存器数目(默认不使用寄存器)。0<=N<=3 ;注意:当N>0时你必须使用同一参数从新构建全部的模块,包括全部的库。 -mmmx -mno-mmx -msse -mno-sse -msse2 -mno-sse2 -msse3 -mno-sse3 -m3dnow -mno-3dnow 上面的这些不用解释了,一看就明白,根据本身的CPU决定吧 -maccumulate-outgoing-args 指定在函数引导段中计算输出参数所需最大空间,这在大部分现代cpu中是较快的方法;缺点是会增长代码尺寸。 -mthreads 支持Mingw32的线程安全异常处理。对于依赖于线程安全异常处理的程序,必须启用这个选项。 使用这个选项时会定义"-D_MT",它将包含使用选项"-lmingwthrd"链接的一个特殊的线程辅助库,用于为每一个线程清理异常处理数据。 -minline-all-stringops 嵌入全部的字符串操做。能够提升字符串操做的性能,可是会增长代码尺寸。 -momit-leaf-frame-pointer 不为叶子函数在寄存器中保存栈指针,这样能够节省寄存器,可是将会是调试变的困难。参见"-fomit-frame-pointer"。 下面这几个仅用于x86_64环境: -m64 生成专门运行于64位环境的代码,不能运行于32位环境 -mcmodel=small [默认值]程序和它的符号必须位于2GB如下的地址空间。指针仍然是64位。程序能够静态链接也能够动态链接。 -mcmodel=kernel 内核运行于2GB地址空间以外。在编译linux内核时必须使用该选项! -mcmodel=medium 程序必须位于2GB如下的地址空间,可是它的符号能够位于任何地址空间。程序能够静态链接也能够动态链接。 注意:共享库不能使用这个选项编译! -mcmodel=large 对地址空间没有任何限制,这个选项的功能目前还没有实现。 ============================== 既然已经讲了这么多了索性再讲讲gcc使用的一些环境变量 除了大名鼎鼎的CFLAGS和CXXFLAGS之外(实际上是Autoconf的环境变量),再挑几个说说: 全部的PATH类环境变量(除LD_RUN_PATH外)都是用冒号分割的目录列表。 C_INCLUDE_PATH 编译C程序时使用的环境变量,用于查找头文件。 CPLUS_INCLUDE_PATH 编译C++程序时使用的环境变量,用于查找头文件。 OBJC_INCLUDE_PATH 编译Obj-C程序时使用的环境变量,用于查找头文件。 CPATH 编译C/C++/Obj-C程序时使用的环境变量,用于查找头文件。 COMPILER_PATH 若是没有用GCC_EXEC_PREFIX定位子程序,编译程序将会在此查找它的子程序。 LIBRARY_PATH 链接程序将在这些目录中寻找特殊的链接程序文件。 LD_LIBRARY_PATH 该环境变量不影响编译程序,可是程序运行的时候会有影响:程序会查找该目录列表以寻找共享库。 当不可以在编译程序的目录中找到共享库的时候,执行程序必须设置该环境变量。 LD_RUN_PATH 该环境变量不影响编译程序,可是程序运行的时候会有影响:它在运行时指出了文件的名字,运行的程序能够由此获得它的符号名字和地址。 因为地址不会从新载入,于是可能符号应用其余文件中的绝对地址。这个和ld工具使用的"-R"选项彻底同样。 GCC_EXEC_PREFIX 编译程序执行全部子程序的名字的前缀,默认值是"<prefix>/lib/gcc-lib/", 其中的<prefix>是安装时configure脚本指定的前缀。 LANG 指定编译程序使用的字符集,可用于建立宽字符文件、串文字、注释;默认为英文。[目前只支持日文"C-JIS,C-SJIS,C-EUCJP",不支持中文] LC_ALL 指定多字节字符的字符分类,主要用于肯定字符串的字符边界以及编译程序使用何种语言发出诊断消息;默认设置与LANG相同。 中文相关的几项:"zh_CN.GB2312 , zh_CN.GB18030 , zh_CN.GBK , zh_CN.UTF-8 , zh_TW.BIG5" TMPDIR 编译程序存放临时工做文件的临时目录,这些临时文件一般在编译结束时被删除。