Gcc
Table of Contents
1. GCC 简介
GCC stands for “GNU Compiler Collection”. GCC is an integrated distribution of compilers for several major programming languages. These languages currently include C, C++, Objective-C, Objective-C++, Java, Fortran, Ada, and Go. The name historically stood for “GNU C Compiler”, and this usage is still common when the emphasis is on compiling C programs.
GCC website: https://gcc.gnu.org/
GCC online documentation: https://gcc.gnu.org/onlinedocs/
GCC Manual: https://gcc.gnu.org/onlinedocs/gcc/
GCC Internals Manual: https://gcc.gnu.org/onlinedocs/gccint/
GCC Releases: https://www.gnu.org/software/gcc/releases.html
2. GCC 命令行选项
2.1. 基本选项
GCC 基本选项如表 1 所示。
GCC 选项 | 说明 |
---|---|
-v | 打开 verbose 模式 |
-Wall | 打开所有 warning |
-O | 优化代码。-O 相当于-O1。指定-O2 或-O3 可进行更大优化,指定-O0 可禁止优化。同时指定多个-O 时仅最后一个生效。 |
-g | 增加调试符号信息。指定-g 并不隐含着禁止优化。 |
-E | 仅预处理,不编译 |
-S | 预处理和编译(生成汇编源码),但不汇编为目标文件 |
-c | 编译和汇编,但不链接 |
-o file | 指定输出文件的名字,输出文件可能是 executable file, object file, assembler file or preprocessed C code. |
-Idir | Add the directory dir to the head of the list of directories to be searched for header files. |
-llibrary | Search the library named library when linking |
-Ldir | Add directory dir to the list of directories to be searched for -l. |
2.1.1. 指定 C 标准 (-std)
指定 gcc 使用 1990 年的标准(c89 和 c90 是同义的,标准化工作从 1989 年开始):
gcc -ansi prog.c # -ansi在编译C时相当于-std=c89,编译C++时相当于-std=c++98 gcc -std=c89 prog.c gcc -std=c90 prog.c
指定 gcc 使用 1999 年的 C 标准:
gcc -std=c99 prog.c
注:如果没有显示指定,gcc 会默认使用-std=gnu89 来编译 C 语言,它在 c89 的基础上包含了一些 c99 的特性,还包含了与 gcc 相关的一些特性。
2.2. 实用选项
2.2.1. -fomit-frame-pointer
-fomit-frame-pointer 表示省略帧指针(即%ebp 寄存器不再保存帧指针)。
从 GCC 4.6 开始,针对 X86 平台的 32-bit 程序,-fomit-frame-pointer 已经是默认选项了!
http://gcc.gnu.org/gcc-4.6/changes.html
如果需要保留帧指针,则可以指定: -fno-omit-frame-pointer
2.2.2. -fstack-protector
- -fstack-protector
- Emit extra code to check for buffer overflows, such as stack smashing attacks. This is done by adding a guard variable to functions with vulnerable objects. This includes functions that call alloca, and functions with buffers larger than 8 bytes. The guards are initialized when a function is entered and then checked when the function exits. If a guard check fails, an error message is printed and the program exits.
- -fstack-protector-all
- Like -fstack-protector except that all functions are protected.
- -fstack-protector-strong
- Like -fstack-protector but includes additional functions to be protected — those that have local array definitions, or have references to local frame addresses.
- -fstack-protector-explicit
- Like -fstack-protector but only protects those functions which have the stack_protect attribute
注:-fstack-protector 可以防止堆栈溢出。
参考:
https://en.wikipedia.org/wiki/Buffer_overflow_protection
https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
http://www.ibm.com/developerworks/cn/linux/l-cn-gccstack/
http://www.thegeekstuff.com/2013/02/stack-smashing-attacks-gcc/
2.2.3. -Wsequence-point
- -Wsequence-point
- Warn about code that may have undefined semantics because of violations of sequence point rules in the C and C++ standards.
This warning is enabled by -Wall for C and C++.
请永远不要写这样的代码,因为它们的行为不明确:
a = a++; a[n] = b[n++]; a[i++] = i;
参考:
浅谈 C/C++中的顺序点和副作用:http://www.cnblogs.com/dolphin0520/archive/2011/04/20/2022330.html
2.2.4. -finstrument-functions
-finstrument-functions
Generate instrumentation calls for entry and exit to functions. Just after function entry and just before function exit.
参考:
https://balau82.wordpress.com/2010/10/06/trace-and-profile-function-calls-with-gcc/
http://linuxgazette.net/151/melinte.html
https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options
2.2.5. -fno-asynchronous-unwind-tables(禁止产生.cfi_xxx)
先做个测试:编译一个简单的 C 程序为汇编代码
测试环境:Ubuntu 14.04, gcc 4.9
$ cat fun1.c int fun1(void){ return 0; } $ gcc -S fun1.c && cat fun1.s .file "fun1.c" .text .globl fun1 .type fun1, @function fun1: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl $0, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size fun1, .-fun1 .ident "GCC: (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2" .section .note.GNU-stack,"",@progbits
发现汇编代码中有很多.cfi 为前缀的指令,它们是什么呢?
cfi stands for Call Frame Information.
Call Frame Information 在 Dwarf 的文档中有介绍。
参见 as 文档:
https://sourceware.org/binutils/docs-2.17/as/CFI-directives.html
2.2.5.1. Call Frame Information 有什么用
Modern ABIs don't require frame pointers to be used in functions. However missing FPs bring difficulties when doing a backtrace. One solution is to provide Dwarf-2 CFI data for each such function.
2.2.5.2. 如何不产生 Call Frame Information
指定 gcc 的选项 -fno-asynchronous-unwind-tables
即可禁止产生 Call Frame Information.
$ gcc -fno-asynchronous-unwind-tables -S fun1.c && cat fun1.s .file "fun1.c" .text .globl fun1 .type fun1, @function fun1: pushq %rbp movq %rsp, %rbp movl $0, %eax popq %rbp ret .size fun1, .-fun1 .ident "GCC: (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2" .section .note.GNU-stack,"",@progbits
2.2.6. Passing options to Assembler, Preprocessor, Linker
GCC 可以通过表 2 所示的选项向汇编器、预处理器、链接器传递参数。
gcc options | 描述 |
---|---|
-Wa,option | Pass option as an option to the assembler. If option contains commas, it is split into multiple options at the commas. |
-Xassember option | Pass option as an option to the assembler. If you want to pass an option that takes an argument, you must use -Xassembler twice, once for the option and once for the argument. |
-Wp,option | Pass option as an option to the preprocessor. |
-Xpreprocessor option | Pass option as an option to the preprocessor. |
-Wl,option | Pass option as an option to the linker. |
-Xlinker option | Pass option as an option to the linker. |
2.3. 影响 GCC 的环境变量
影响 GCC 及其预处理器的环境变量分别如表 3 和表 4 所示。
environment variable | 说明 |
---|---|
LANG | This variable is used to pass locale information to the compiler. LC_CTYPE and LC_MESSAGES default to the value of the LANG environment variable. |
LC_CTYPE | Specifies character classification. GCC uses it to determine the character boundaries in a string; this is needed for some multibyte encodings that contain quote and escape characters that are otherwise interpreted as a string end or escape. |
LC_MESSAGES | Specifies the language to use in diagnostic messages |
LC_ALL | If the LC_ALL environment variable is set, it overrides the value of LC_CTYPE and LC_MESSAGES |
TMPDIR | If TMPDIR is set, it specifies the directory to use for temporary files. |
GCC_COMPARE_DEBUG | Setting GCC_COMPARE_DEBUG is nearly equivalent to passing -fcompare-debug to the compiler driver. |
GCC_EXEC_PREFIX | If GCC_EXEC_PREFIX is set, it specifies a prefix to use in the names of the subprograms executed by the compiler. |
COMPILER_PATH | GCC tries the directories thus specified when searching for subprograms, if it can't find the subprograms using GCC_EXEC_PREFIX. |
LIBRARY_PATH | GCC uses these directories when searching for ordinary libraries for the -l option (but directories specified with -L come first). |
environment variable | 说明 |
---|---|
CPATH | 用于指定头文件的搜索,相当于用-I 指定目录。GCC 先在-I 指定目录中查找头文件,找不到再在 CPATH 中查找。可用于预处理所有语言(如 C, C++, Objective-C 等等)。 |
C_INCLUDE_PATH | 相当于用-isystem 指定目录,优先级比用-isystem 指定的目录低。仅用于预处理 C 语言源码。 |
CPLUS_INCLUDE_PATH | 相当于用-isystem 指定目录,优先级比用-isystem 指定的目录低。仅用于预处理 C++语言源码。 |
OBJC_INCLUDE_PATH | 相当于用-isystem 指定目录,优先级比用-isystem 指定的目录低。仅用于预处理 Objective-C 语言源码。 |
DEPENDENCIES_OUTPUT | This variable is equivalent to combining the options -MM and -MF (see Preprocessor Options), with an optional -MT switch too. |
SUNPRO_DEPENDENCIES | This variable is the same as DEPENDENCIES_OUTPUT, except that system header files are not ignored, so it implies -M rather than -MM. |
参考:https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
3. GNU Linker (ld) options
gcc can pass option as an option to the linker by using -Wl,option
.
If option contains commas, it is split into multiple options at the commas. You can use this syntax to pass an argument to the option. For example, -Wl,-Map,output.map passes -Map output.map to the linker. When using the GNU linker, you can also get the same effect with -Wl,-Map=output.map.
References:
gcc options for linking: https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options
GNU Linker (ld) options: https://sourceware.org/binutils/docs/ld/Options.html#Options
3.1. 链接时检测动态库中的 unresolved symbols (-no-undefined
)
用链接器的 -z defs
或 -no-undefined
可以检测 unresolved symbols。
$ cat silly.c #include <stdio.h> void forgot_to_define(FILE *fp); void doit(const char *filename) { FILE *fp = fopen(filename, "r"); if (fp != NULL) { forgot_to_define(fp); fclose(fp); } } $ gcc -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed succeeded $ gcc -Wl,z,defs -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed /tmp/ccmfaNa8.o: In function `doit': silly.c:(.text+0x35): undefined reference to `forgot_to_define' collect2: ld returned 1 exit status failed
参考:http://stackoverflow.com/questions/1617286/easy-check-for-unresolved-symbols-in-shared-libraries
3.2. ld 如何搜索共享库
The linker uses the following search paths to locate required shared libraries:
- Any directories specified by -rpath-link options.
- Any directories specified by -rpath options. The difference between -rpath and -rpath-link is that directories specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is only effective at link time. Searching -rpath in this way is only supported by native linkers and cross linkers which have been configured with the --with-sysroot option.
- On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of the environment variable LD_RUN_PATH.
- On SunOS, if the -rpath option was not used, search any directories specified using -L options.
- For a native linker, search the contents of the environment variable LD_LIBRARY_PATH.
- For a native ELF linker, the directories in DT_RUNPATH or DT_RPATH of a shared library are searched for shared libraries needed by it. The DT_RPATH entries are ignored if DT_RUNPATH entries exist.
- The default directories, normally /lib and /usr/lib.
- For a native linker on an ELF system, if the file /etc/ld.so.conf exists, the list of directories found in that file.
If the required shared library is not found, the linker will issue a warning and continue with the link.
4. GIMPLE
GIMPLE is a family of intermediate representations (IR) based on the tree data structure.
The gcc argument options -fdump-tree-all
-fdump-tree-ssa
-fdump-tree-optimized
etc. might be used to have some GIMPLE intermediate representations dumped (in a simpler textual form).
参考:
https://gcc.gnu.org/wiki/GIMPLE
https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
5. Tips
5.1. 术语 winding 和 unwinding 是什么意思
Adding a subroutine's entry to the call stack is sometimes called "winding"; conversely, removing entries is "unwinding".
5.2. 查看 include path
使用下面命令可以查看编译器会搜索的 include path:
$ gcc -E -Wp,-v -xc /dev/null $ g++ -E -Wp,-v -xc++ /dev/null
5.3. 查看当前系统的 GLIBC 版本
如何查看当前系统的 GLIBC 版本?
方法 1:
$ ldd --version GNU C Library stable release version 2.5, by Roland McGrath et al. Copyright (C) 2006 Free Software Foundation, Inc.
方法 2:
$ /lib/libc.so.6 GNU C Library stable release version 2.5, by Roland McGrath et al. Copyright (C) 2006 Free Software Foundation, Inc.