100个gcc小技巧
|
|
|
|
|
|
|
|
|
|
|
|
|
|
目錄 |
|
|
|||||
|
|
0 |
|||||||||||||||||||
|
|
1 |
|||||||||||||||||||
|
1.1 |
||||||||||||||||||||
|
1.2 |
||||||||||||||||||||
|
1.3 |
||||||||||||||||||||
|
1.4 |
||||||||||||||||||||
|
1.5 |
||||||||||||||||||||
|
1.6 |
||||||||||||||||||||
|
|
2 |
|||||||||||||||||||
|
2.1 |
||||||||||||||||||||
|
2.2 |
||||||||||||||||||||
|
2.3 |
||||||||||||||||||||
|
|
3 |
|||||||||||||||||||
|
3.1 |
||||||||||||||||||||
|
3.2 |
||||||||||||||||||||
|
|
4 |
|||||||||||||||||||
|
4.1 |
||||||||||||||||||||
|
4.2 |
||||||||||||||||||||
|
|
5 |
|||||||||||||||||||
|
5.1 |
||||||||||||||||||||
|
5.2 |
||||||||||||||||||||
|
|
6 |
|||||||||||||||||||
|
6.1 |
||||||||||||||||||||
|
6.2 |
||||||||||||||||||||
|
|
7 |
|||||||||||||||||||
|
7.1 |
||||||||||||||||||||
|
7.2 |
||||||||||||||||||||
gdb无法调试gcc编译的程序 |
|
7.3 |
|||||||||||||||||||
|
|
8 |
|||||||||||||||||||
|
8.1 |
||||||||||||||||||||
|
8.2 |
||||||||||||||||||||
|
8.3 |
||||||||||||||||||||
|
8.4 |
||||||||||||||||||||
|
8.5 |
2
100个gcc小技巧
《100个gcc小技巧》
作者:hellogcc
一个关于gcc使用小技巧的文档。100,在这里可能只是表明很多;具体的数目取决 于您的参与和贡献。
在线阅读
如何参与
直接发PULL REQUEST,或与我们联系。
增加一个小技巧的步骤:
1.在src目录下新增一个md文件,参照现有文件的格式风格,编写一个小技巧 markdown语法参见 http://wowubuntu.com/markdown/ md文件编写可以使用在线所见即所得编辑器 https://www.zybuluo.com/mdeditor
2.在index.md中为新md文件增加一个索引,可以放到已有分类中,或增加一个 分类
3.如果预览下没有问题,OK!
本地生成html的步骤:
2.直接运行build.sh
3.如果顺利,会在html目录下生成所有的html文件
联系方式
在线讨论问题:IRC, freenode, #hellogcc房间 邮件列表 (发信需要先订阅)
版权
本文档版权归贡献者所有。
介紹 |
3 |
100个gcc小技巧
信息显示
信息显示 |
5 |
100个gcc小技巧
打印gcc预定义的宏信息
例子
[root@linux:~]$ gcc
#define __FLT_MIN__
#define __WCHAR_MAX__ 2147483647
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1 #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1 #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 #define __DBL_DENORM_MIN__
#define __unix__ 1 #define __x86_64 1
#define __DBL_MIN_10_EXP__
技巧
如上所示,使用“ gcc
贡献者
nanxiao
打印gcc预定义的宏信息 |
6 |
100个gcc小技巧
打印gcc执行的子命令
例子
$gcc
Configured with: ../src/configure
Thread model: posix
gcc version 4.6.3 (Ubuntu/Linaro
as
技巧
如上所示,使用
cc1:
as:
as
collect2:
打印gcc执行的子命令 |
7 |
100个gcc小技巧
这个跟使用
贡献者
xmj
打印gcc执行的子命令 |
8 |
100个gcc小技巧
打印优化级别的对应选项
例子
$ gcc
The following options control optimizations:
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[enabled] |
|||
[enabled] |
|
||
[disabled] |
|
||
[disabled] |
|
||
[disabled] |
|
|
|
[disabled] |
|
||
[disabled] |
|||
[disabled] |
|||
[enabled] |
|
||
[disabled] |
|
||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[enabled] |
|
||
[disabled] |
|
||
[disabled] |
|||
[enabled] |
|||
[disabled] |
|||
[enabled] |
|
||
[enabled] |
|
||
[disabled] |
|
||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[disabled] |
|||
[enabled] |
|
||
[disabled] |
|
||
[disabled] |
打印优化级别的对应选项 |
9 |
100个gcc小技巧
[disabled] |
|
||||
|
|
|
|
|
|
|
[disabled] |
|
|||
[disabled] |
|
||||
[disabled] |
|
||||
[enabled] |
|
|
|
||
[disabled] |
|
|
|
||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[enabled] |
|
|
|||
[enabled] |
|
||||
[disabled] |
|
|
|||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
[disabled] |
|
||||
[disabled] |
|
||||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
|
|
|
|
|
|
|
[disabled] |
|
|||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
|
|||||
[disabled] |
|
||||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
[disabled] |
|
||||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
[disabled] |
|
|
|||
[disabled] |
|
|
|||
|
|||||
[disabled] |
|
||||
|
[disabled] |
||||
[disabled] |
|
||||
|
|
||||
[enabled] |
|
||||
[enabled] |
|
||||
[enabled] |
|
打印优化级别的对应选项 |
10 |
100个gcc小技巧
[enabled] |
|
|
|
||
[enabled] |
|
|
|
||
[enabled] |
|
|
|
||
[disabled] |
|
|
|
||
[enabled] |
|
|
|
||
[enabled] |
|
|
|||
[enabled] |
|
|
|||
[disabled] |
|
|
|
||
[disabled] |
|
|
|||
[disabled] |
|
|
|||
[enabled] |
|
|
|
||
[disabled] |
|
|
|
||
[disabled] |
|
|
|||
[disabled] |
|
|
|||
[disabled] |
|
|
|||
[disabled] |
|
|
|||
[disabled] |
|||||
[disabled] |
|
||||
[disabled] |
|
|
|||
[disabled] |
|
||||
[disabled] |
|
||||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
|
|||||
[disabled] |
|
||||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[enabled] |
|
|
|||
[enabled] |
|
||||
[enabled] |
|
||||
[disabled] |
|
|
|||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[disabled] |
|
||||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
|
|||||
[disabled] |
|
||||
[disabled] |
|
||||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
|
|||||
[disabled] |
|
||||
[disabled] |
|
||||
[enabled] |
|
|
|||
[disabled] |
|
|
|||
[enabled] |
|
|
|||
[enabled] |
|
打印优化级别的对应选项 |
11 |
100个gcc小技巧
[enabled] |
|
|
|
|
[disabled] |
|
|
|
|
[enabled] |
|
|
|
|
[disabled] |
|
|
|
|
[enabled] |
|
|
|
|
[enabled] |
|
|
||
[enabled] |
|
|
||
[disabled] |
|
|
|
|
[enabled] |
|
|
|
|
[disabled] |
|
|
|
|
|
||||
[disabled] |
|
|
||
[disabled] |
|
|
||
[enabled] |
|
|
|
|
[disabled] |
|
|
|
|
|
||||
[disabled] |
|
|
||
[enabled] |
|
|
|
|
[disabled] |
|
|
|
|
[disabled] |
|
|
||
[disabled] |
|
|
||
[disabled] |
|
|
||
[disabled] |
|
|
||
[disabled] |
|
|
||
[enabled] |
|
|
|
|
[enabled] |
|
|
||
[disabled] |
||||
[disabled] |
|
|
||
[disabled] |
|
|
||
|
||||
[enabled] |
|
|
||
[disabled] |
|
|
||
[enabled] |
|
|
||
[disabled] |
|
|
||
|
||||
[disabled] |
|
|||
[disabled] |
|
技巧
如上所示,使用
$gcc
$gcc
$gcc
$gcc
$gcc
$gcc
$gcc
打印优化级别的对应选项 |
12 |
100个gcc小技巧
贡献者
xmj
打印优化级别的对应选项 |
13 |
100个gcc小技巧
打印彩色诊断信息
技巧
也可以使用选项
贡献者
xmj
打印彩色诊断信息 |
14 |
100个gcc小技巧
打印头文件搜索路径
例子
$gcc
...
ignoring nonexistent directory
#include <...> search starts
/usr/include
End of search list.
...
技巧
如上所示,使用
贡献者
xmj
打印头文件搜索路径 |
15 |
100个gcc小技巧
打印连接库的具体路径
例子
$ gcc
技巧
如上所示,使用
贡献者
xmj
打印连接库的具体路径 |
16 |
100个gcc小技巧
预处理
预处理 |
17 |
100个gcc小技巧
生成没有行号标记的预处理文件
技巧
有时编译程序会遇到如下类似的错误,
In file included from foo.c:15, from a.h:45,
b.h:53: error: ... ...
如果错误是由于你所定义的一个很复杂的宏所引起的,你可能会需要先手动编译生 成相应的预处理文件,查看下预处理文件中的宏扩展代码。比如,先运行
gcc
来生成foo.i预处理文件。然后,还可以尝试手动修改、编译这个预处理文件。
但是,由于生成的预处理文件中含有行号标记(linemarker),所以,运行
gcc
所得到的错误行号信息还是跟最初的一样,如果可以将预处理文件中的行号标记都 去掉,似乎会有些帮助。
幸好,gcc提供了这个选项:
运行
gcc
即可。
贡献者
生成没有行号标记的预处理文件 |
18 |
100个gcc小技巧
xmj
生成没有行号标记的预处理文件 |
19 |
100个gcc小技巧
在命令行中预定义宏
例子
#include <stdio.h>
int main (void)
{
int i, sum;
for (i = 1, sum = 0; i <= 10; i++)
{
sum += i; #ifdef DEBUG
printf ("sum += %d is %d\n", i, sum); #endif
}
printf ("total sum is %d\n", sum);
return 0;
}
技巧
使用
$ gcc
中间可以没有空格:
$ gcc
贡献者
xmj
在命令行中预定义宏 |
20 |
100个gcc小技巧
在命令行中取消宏定义
技巧
类似于
$ gcc
中间可以没有空格:
$ gcc
贡献者
xmj
在命令行中取消宏定义 |
21 |
100个gcc小技巧
汇编
汇编 |
22 |
100个gcc小技巧
把选项传给汇编器
例子
#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i < 10; i++) printf("%d ", i);
putchar ('\n');
return 0;
}
技巧
使用
注意,逗号和选项之间不能有空格。例如:
把选项传给汇编器 |
23 |
100个gcc小技巧
$gcc
$objdump
foo.o: file format
Disassembly of section .text: |
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|||
0000000000000000 |
<main>: |
|
|
|
|
|
|
|
|||||
0: |
55 |
|
|
|
|
|
push |
%rbp |
|
|
|
|
|
1: |
48 |
89 |
e5 |
|
|
|
mov |
%rsp,%rbp |
|
|
|
||
4: |
48 |
83 |
ec |
10 |
|
|
sub |
$0x10,%rsp |
|
|
|
||
8: |
c7 |
45 |
fc |
00 00 |
00 00 |
movl |
|||||||
f: |
eb 1b |
|
|
|
|
jmp |
2c <.L2> |
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|||
0000000000000011 |
<.L3>: |
|
|
|
|
|
|
|
|
|
|||
11: |
b8 |
00 |
00 |
00 00 |
|
|
mov |
$0x0,%eax |
|
|
|||
16: |
8b |
55 |
fc |
|
|
|
mov |
||||||
19: |
89 |
d6 |
|
|
|
|
mov |
%edx,%esi |
|
|
|||
1b: |
48 |
89 |
c7 |
|
|
|
mov |
%rax,%rdi |
|
|
|||
1e: |
b8 |
00 |
00 |
00 00 |
|
|
mov |
$0x0,%eax |
|
|
|||
23: |
e8 |
00 |
00 |
00 00 |
|
|
callq |
28 <.L3+0x17> |
|
||||
28: |
83 |
45 |
fc |
01 |
|
|
addl |
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|||
000000000000002c |
<.L2>: |
|
|
|
|
|
|
|
|
|
|||
2c: |
83 |
7d |
fc |
09 |
|
|
cmpl |
||||||
30: |
7e |
df |
|
|
|
|
jle |
11 <.L3> |
|
||||
32: |
bf 0a 00 |
00 00 |
|
|
mov |
$0xa,%edi |
|
|
|||||
37: |
e8 |
00 |
00 |
00 00 |
|
|
callq |
3c <.L2+0x10> |
|
||||
3c: |
b8 |
00 |
00 |
00 00 |
|
|
mov |
$0x0,%eax |
|
|
|||
41: |
c9 |
|
|
|
|
|
leaveq |
|
|
|
|
|
|
42: |
c3 |
|
|
|
|
|
retq |
|
|
|
|
|
|
这里的
如果此时你使用 oprofile 来统计性能事件,那么获得的结果将不是以函数为单位 了,而是以这些符号所划分的代码块为单位。
贡献者
xmj
把选项传给汇编器 |
24 |
100个gcc小技巧
生成有详细信息的汇编文件
例子
#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i < 10; i++) printf("%d ", i);
putchar ('\n');
return 0;
}
技巧
使用
$gcc
$cat foo.s
.file "foo.c"
#GNU C (Ubuntu/Linaro
#compiled by GNU C version 4.6.3, GMP version 5.0.2, MPFR vers
#GGC heuristics:
#options passed:
#
#options enabled:
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
生成有详细信息的汇编文件 |
25 |
100个gcc小技巧
#
#
#
#
#
#Compiler executable checksum: 75e879ed14f91af504f4150eadeaa0e6
|
.section |
.rodata |
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||
|
.LC0: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.string |
|
"%d " |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
.text |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
.globl |
|
|
main |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
.type |
main, |
@function |
|
|
|
|
|
|
|
|
||||||||||||||||
|
main: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
.LFB0: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
.cfi_startproc |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||
|
pushq |
%rbp |
|
|
# |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
.cfi_def_cfa_offset |
16 |
|
|
|
|
|
|
|
|
|
|
|||||||||||||||
|
.cfi_offset 6, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||
|
movq |
%rsp, %rbp |
|
#, |
|
|
|
|
|
|
|
|
|||||||||||||||
|
.cfi_def_cfa_register 6 |
|
|
|
|
|
|
|
|
|
|||||||||||||||||
|
subq |
$16, %rsp |
|
|
|
#, |
|
|
|
|
|
|
|
|
|
||||||||||||
|
movl |
$0, |
|
|
|
|
#, i |
|
|
|
|
|
|
|
|||||||||||||
|
jmp |
.L2 |
# |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
.L3: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
movl |
$.LC0, %eax |
|
|
#, D.2049 |
|
|
|
||||||||||||||||||
|
movl |
# i, |
tmp62 |
|
|
||||||||||||||||||||||
|
movl |
%edx, %esi |
|
# tmp62, |
|
|
|
|
|||||||||||||||||||
|
movq |
%rax, %rdi |
|
# D.2049, |
|
|
|
||||||||||||||||||||
|
movl |
$0, %eax |
|
|
|
#, |
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
call |
printf |
# |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
addl |
$1, |
|
|
|
|
|
#, i |
|
|
|
||||||||||||||||
|
.L2: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
cmpl |
$9, |
|
|
|
|
#, i |
|
|
|
||||||||||||||||
|
jle |
.L3 |
#, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
movl |
$10, %edi |
|
|
|
|
#, |
|
|
|
|
|
|
|
|
|
|||||||||||
|
call |
putchar |
# |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||
|
movl |
$0, %eax |
|
|
|
#, D.2050 |
|
|
|||||||||||||||||||
|
leave |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
.cfi_ |
def_cfa 7, 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
.cfi |
_endproc |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||
|
.LFE0: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
.size |
|
|
|
|
|
|
|
|
|
|||||||||||||||||
|
.ident |
|
"GCC: (Ubuntu/Linaro |
|
|||||||||||||||||||||||
|
.section |
|
|||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
可以看到,在汇编文件中给出了gcc所使用的具体选项,以及汇编指令操作数所对 应的源程序(或中间代码)中的变量。
生成有详细信息的汇编文件 |
26 |
100个gcc小技巧
调试
调试 |
28 |
100个gcc小技巧
利用Address Sanitizer工具检查内存访问错误
例子
a.c:
#include <stdio.h>
int main(void) {
//your code goes here int a[3] = {0};
a[3] = 1;
printf("%d\n", a[3]); return 0;
}
b.c:
#include <stdio.h> #include <malloc.h>
int main(void) {
int *p = NULL;
p = malloc(10 * sizeof(int)); free(p);
*p = 3; return 0;
}
技巧
gcc从 4.8 版本起,集成了 Address Sanitizer 工具,可以用来检查内存访问的 错误(编译时指定“
gcc
执行 a 程序:
利用Address Sanitizer工具检查内存访问错误 |
29 |
100个gcc小技巧
[root@localhost nan]# ./a
=================================================================
==539==ERROR: AddressSanitizer:
#0 0x4009b5 in main /home/nan/a.c:6
#1 0x34e421ed1c in __libc_start_main (/lib64/libc.so.6+0x34e42 #2 0x4007b8 (/home/nan/a+0x4007b8)
Address 0x7fff3a152c9c is located in stack of thread T0 at offset #0 0x400907 in main /home/nan/a.c:3
This frame has 1 object(s):
[32, 44) 'a' <== Memory access at offset 44 overflows this var
HINT: this may be a false positive if your program uses some custo (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer:
0x100067422540: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100067422550: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100067422560: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100067422570: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100067422580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 =>0x100067422590: f1 f1 00[04]f4 f4 f3 f3 f3 f3 00 00 00 00 00 00 0x1000674225a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x1000674225b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x1000674225c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x1000674225d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x1000674225e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes
Addressable: |
00 |
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: |
fa |
Heap right redzone: |
fb |
Freed heap region: |
fd |
Stack left redzone: |
f1 |
Stack mid redzone: |
f2 |
Stack right redzone: |
f3 |
Stack partial redzone: |
f4 |
Stack after return: |
f5 |
Stack use after scope: f8 |
|
Global redzone: |
f9 |
Global init order: |
f6 |
Poisoned by user: |
f7 |
Contiguous container OOB:fc |
|
ASan internal: |
fe |
==539==ABORTING
可以看到,执行程序时检测出了 a 数组的越界访问( a[3] = 1 )。
再看一下 b 程序:
利用Address Sanitizer工具检查内存访问错误 |
30 |
100个gcc小技巧
gcc
执行 b 程序:
利用Address Sanitizer工具检查内存访问错误 |
31 |
100个gcc小技巧
[root@localhost nan]# ./b
=================================================================
==1951==ERROR: AddressSanitizer:
#0 0x4007f8 in main /home/nan/b.c:9
#1 0x34e421ed1c in __libc_start_main (/lib64/libc.so.6+0x34e42 #2 0x400658 (/home/nan/b+0x400658)
0x60400000dfd0 is located 0 bytes inside of
#0 0x7fbbb7a7d057 in
#2 0x34e421ed1c in __libc_start_main (/lib64/libc.so.6+0x34e42
previously allocated by thread T0 here:
#0 0x7fbbb7a7d26f in
#2 0x34e421ed1c in __libc_start_main (/lib64/libc.so.6+0x34e42
SUMMARY: AddressSanitizer:
|
0x0c087fff9ba0: fa fa |
fa |
fa fa fa |
fa fa fa fa fa fa fa fa fa fa |
|
||
|
0x0c087fff9bb0: fa fa |
fa |
fa fa fa |
fa fa fa fa fa fa fa fa fa fa |
|
||
|
0x0c087fff9bc0: fa fa |
fa |
fa fa fa |
fa fa fa fa fa fa fa fa fa fa |
|
||
|
0x0c087fff9bd0: fa fa |
fa |
fa fa fa |
fa fa fa fa fa fa fa fa fa fa |
|
||
|
0x0c087fff9be0: fa fa |
fa |
fa fa fa |
fa fa fa fa fa fa fa fa fa fa |
|
||
|
=>0x0c087fff9bf0: fa fa |
fa |
fa fa fa |
fa fa fa fa[fd]fd fd fd fd fa |
|
||
|
0x0c087fff9c00: fa fa |
fa |
fa fa fa |
fa fa fa fa fa fa fa fa fa fa |
|
||
|
0x0c087fff9c10: fa fa |
fa |
fa fa fa |
fa fa fa fa fa fa fa fa fa fa |
|
||
|
0x0c087fff9c20: fa fa |
fa |
fa fa fa |
fa fa fa fa fa fa fa fa fa fa |
|
||
|
0x0c087fff9c30: fa fa |
fa |
fa fa fa |
fa fa fa fa fa fa fa fa fa fa |
|
||
|
0x0c087fff9c40: fa fa |
fa fa fa fa |
fa fa fa fa fa fa fa fa fa fa |
|
|||
|
Shadow byte legend (one |
shadow byte represents 8 application bytes |
|
||||
|
Addressable: |
00 |
|
|
|
|
|
|
Partially addressable: 01 |
02 03 04 05 06 07 |
|
||||
|
Heap left redzone: |
|
fa |
|
|
|
|
|
Heap right redzone: |
|
fb |
|
|
|
|
|
Freed heap region: |
|
fd |
|
|
|
|
|
Stack left redzone: |
|
f1 |
|
|
|
|
|
Stack mid redzone: |
|
f2 |
|
|
|
|
|
Stack right redzone: |
|
f3 |
|
|
|
|
|
Stack partial redzone: |
|
f4 |
|
|
|
|
|
Stack after return: |
|
f5 |
|
|
|
|
|
Stack use after scope: |
|
f8 |
|
|
|
|
|
Global redzone: |
|
f9 |
|
|
|
|
|
Global init order: |
|
f6 |
|
|
|
|
|
Poisoned by user: |
|
f7 |
|
|
|
|
|
Contiguous container OOB:fc |
|
|
|
|
||
|
ASan internal: |
|
fe |
|
|
|
|
|
==1951==ABORTING |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
利用Address Sanitizer工具检查内存访问错误 |
32 |
100个gcc小技巧
利用Thread Sanitizer工具检查数据竞争的问题
例子
#include <pthread.h> int Global;
void *Thread1(void *x) { Global = 42;
return x;
}
int main(void) {
pthread_t t;
pthread_create(&t, NULL, Thread1, NULL); Global = 43;
pthread_join(t, NULL); return Global;
}
技巧
gcc从 4.8 版本起,集成了 Address Sanitizer 工具,可以用来检查数据竞争的 问题(编译时指定“
gcc
执行 a 程序:
利用Thread Sanitizer工具检查数据竞争的问题 |
34 |
100个gcc小技巧
[root@localhost nan]# ./a
==================
WARNING: ThreadSanitizer: data race (pid=14545) Write of size 4 at 0x7f055b4802b0 by thread T1:
#0 Thread1 /home/nan/a.c:4 (a+0x000000000a87)
Previous write of size 4 at 0x7f055b4802b0 by main thread: #0 main /home/nan/a.c:10 (a+0x000000000ae8)
Location is global 'Global' of size 4 at 0x7f055b4802b0 (a+0x000
Thread T1 (tid=14547, running) created by main thread at:
#0
SUMMARY: ThreadSanitizer: data race /home/nan/a.c:4 Thread1
==================
ThreadSanitizer: reported 1 warnings
可以看到,执行程序时检测出了对 Global 变量的竞争访问。 详情参见gcc手册
贡献者
nanxiao
利用Thread Sanitizer工具检查数据竞争的问题 |
35 |
100个gcc小技巧
#连接
连接 |
36 |
100个gcc小技巧
把选项传给连接器
例子
#include <stdio.h>
int main (void)
{
puts ("Hello world!"); return 0;
}
技巧
使用
注意,逗号和选项之间不能有空格。一种常见用法,就是让连接器生成内存映射文 件,例如:
$gcc
$cat output.map
Archive member included because of file (symbol)
Discarded input sections
.gnu_debuglink |
0x0000000000000000 |
0x0 |
/usr/lib/gcc/x86_64- |
||
|
|
|
|
|
|
|
0x0000000000000000 |
0xc /usr/lib/gcc/x86_64- |
|||
|
|
|
|
||
|
|
0x0000000000000000 |
0x0 |
/usr/lib/gcc/x86_64- |
|
.gnu_debuglink |
|
|
|
|
|
|
0x0000000000000000 |
0xc /usr/lib/gcc/x86_64- |
|||
|
|
|
|
||
|
|
0x0000000000000000 |
0x0 |
/usr/lib/gcc/x86_64- |
|
|
|
|
|
||
|
|
0x0000000000000000 |
0x0 |
/tmp/ccBOhdmq.o |
|
|
|
|
|
||
|
|
0x0000000000000000 |
0x0 |
||
|
|
|
|
||
|
|
0x0000000000000000 |
0x0 |
/usr/lib/gcc/x86_64- |
|
|
|
|
|
把选项传给连接器 |
37 |
100个gcc小技巧
.gnu_debuglink |
|
0x0000000000000000 |
0x0 |
/usr/lib/gcc/x86_64- |
||||
|
|
|
|
|
|
|
||
|
|
|
0x0000000000000000 |
0xc /usr/lib/gcc/x86_64- |
||||
|
|
|
|
|
|
|
|
|
Memory map |
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
** file header |
|
|
|
|
|
|
||
|
|
|
0x0000000000400000 |
0x40 |
|
|
||
** segment headers |
|
|
|
|
||||
|
|
|
|
|
0x0000000000400040 |
0x1f8 |
|
|
|
|
|
|
|
|
|||
.interp |
0x0000000000400238 |
0x1c |
|
|
||||
** fill |
0x0000000000400238 |
0x1c |
|
|
||||
|
|
|
|
|
|
|||
0x0000000000400254 |
0x20 |
|
|
|||||
0x0000000000400254 |
0x20 |
/usr/lib/gcc/x86_64- |
||||||
|
|
|
|
|
|
|||
|
|
|
||||||
|
|
|
|
0x0000000000400274 |
0x24 |
|
|
|
** note header |
|
|
|
|
|
|
|
|
|
|
|
0x0000000000400274 |
0x10 |
|
|
||
** zero fill |
0x0000000000400284 |
0x14 |
|
|
||||
|
|
|
|
|
||||
.dynsym |
0x0000000000400298 |
0x78 |
|
|
||||
** dynsym |
0x0000000000400298 |
0x78 |
|
|
||||
|
|
|
|
|
||||
.dynstr |
0x0000000000400310 |
0x51 |
|
|
||||
** string table |
|
|
|
|
|
|
||
|
|
|
0x0000000000400310 |
0x51 |
|
|
||
|
|
|
|
|
||||
.gnu.hash |
0x0000000000400368 |
0x1c |
|
|
||||
** hash |
0x0000000000400368 |
0x1c |
|
|
||||
|
|
|
|
|
||||
.gnu.version |
0x0000000000400384 |
0xa |
|
|
||||
** versions |
0x0000000000400384 |
0xa |
|
|
||||
|
|
|
|
|
||||
.gnu.version_r |
0x0000000000400390 |
0x20 |
|
|
||||
** version refs |
|
|
|
|
|
|
||
|
|
|
0x0000000000400390 |
0x20 |
|
|
||
|
|
|
|
|
||||
.rela.dyn |
0x00000000004003b0 |
0x18 |
|
|
||||
** dynamic relocs |
|
|
|
|
||||
|
|
|
|
0x00000000004003b0 |
0x18 |
|
|
|
|
|
|
|
|
||||
.rela.plt |
0x00000000004003c8 |
0x30 |
|
|
||||
** dynamic relocs |
|
|
|
|
||||
|
|
|
|
0x00000000004003c8 |
0x30 |
|
|
|
|
|
|
|
|
||||
.init |
0x00000000004003f8 |
0x18 |
|
|
||||
.init |
0x00000000004003f8 |
0x9 |
/usr/lib/gcc/x86_64- |
|||||
|
|
|
0x00000000004003f8 |
|
_init |
|
||
.init |
0x0000000000400401 |
0x5 |
/usr/lib/gcc/x86_64- |
|||||
.init |
0x0000000000400406 |
0x5 |
/usr/lib/gcc/x86_64- |
把选项传给连接器 |
38 |
100个gcc小技巧
.init |
0x000000000040040b |
0x5 |
/usr/lib/gcc/x86_64- |
|||||||
|
|
|
|
|
|
|
|
|
|
|
.plt |
0x0000000000400410 |
0x30 |
|
|
|
|
|
|
|
|
** PLT |
0x0000000000400410 |
0x30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.text |
0x0000000000400440 |
0x1d8 |
|
|
|
|
|
|
|
|
.text |
0x0000000000400440 |
0x2c |
/usr/lib/gcc/x86_64- |
|||||||
|
0x0000000000400440 |
|
_start |
|
|
|
|
|||
.text |
0x000000000040046c |
0x17 |
/usr/lib/gcc/x86_64- |
|||||||
** fill |
0x0000000000400483 |
0xd |
|
|
|
|
|
|
|
|
.text |
0x0000000000400490 |
0x92 |
/usr/lib/gcc/x86_64- |
|||||||
.text |
0x0000000000400522 |
0x15 |
/tmp/ccBOhdmq.o |
|
|
|
||||
|
0x0000000000400522 |
|
main |
|
|
|
|
|
||
** fill |
0x0000000000400537 |
0x9 |
|
|
|
|
|
|
|
|
.text |
0x0000000000400540 |
0x92 |
||||||||
|
0x0000000000400540 |
|
__libc_csu_init |
|
||||||
|
0x00000000004005d0 |
|
__libc_csu_fini |
|
||||||
** fill |
0x00000000004005d2 |
0xe |
|
|
|
|
|
|
|
|
.text |
0x00000000004005e0 |
0x36 |
/usr/lib/gcc/x86_64- |
|||||||
** fill |
0x0000000000400616 |
0x2 |
|
|
|
|
|
|
|
|
.text |
0x0000000000400618 |
0x0 |
/usr/lib/gcc/x86_64- |
|||||||
|
|
|
|
|
|
|
|
|
|
|
.fini |
0x0000000000400618 |
0xe |
|
|
|
|
|
|
|
|
.fini |
0x0000000000400618 |
0x4 |
/usr/lib/gcc/x86_64- |
|||||||
|
0x0000000000400618 |
|
_fini |
|
|
|||||
.fini |
0x000000000040061c |
0x5 |
/usr/lib/gcc/x86_64- |
|||||||
.fini |
0x0000000000400621 |
0x5 |
/usr/lib/gcc/x86_64- |
|||||||
|
|
|
|
|
|
|
|
|
|
|
.rodata |
0x0000000000400628 |
0x11 |
|
|
|
|
|
|
|
|
** merge constants |
|
|
|
|
|
|
|
|
|
|
|
|
0x0000000000400628 |
0x4 |
|
|
|
|
|
|
|
.rodata |
0x000000000040062c |
0xd |
/tmp/ccBOhdmq.o |
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
.eh_frame |
0x0000000000400640 |
0xa4 |
|
|
|
|
|
|
|
|
** eh_frame |
0x0000000000400640 |
0xa0 |
|
|
|
|
|
|
|
|
.eh_frame |
0x00000000004006e0 |
0x4 |
/usr/lib/gcc/x86_64- |
|||||||
|
|
|
|
|
|
|
|
|
|
|
.eh_frame_hdr 0x00000000004006e4 |
0x2c |
|
|
|
|
|
|
|
||
** eh_frame_hdr |
|
|
|
|
|
|
|
|
|
|
|
0x00000000004006e4 |
0x2c |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.ctors |
0x0000000000401e28 |
0x10 |
|
|
|
|
|
|
|
|
.ctors |
0x0000000000401e28 |
0x8 |
/usr/lib/gcc/x86_64- |
|||||||
.ctors |
0x0000000000401e30 |
0x8 |
/usr/lib/gcc/x86_64- |
|||||||
|
|
|
|
|
|
|
|
|
|
|
.dtors |
0x0000000000401e38 |
0x10 |
|
|
|
|
|
|
|
|
.dtors |
0x0000000000401e38 |
0x8 |
/usr/lib/gcc/x86_64- |
|||||||
.dtors |
0x0000000000401e40 |
0x8 |
/usr/lib/gcc/x86_64- |
|||||||
|
0x0000000000401e40 |
|
__DTOR_END__ |
|
||||||
|
|
|
|
|
|
|
|
|
|
|
.jcr |
0x0000000000401e48 |
0x8 |
|
|
|
|
|
|
|
|
.jcr |
0x0000000000401e48 |
0x0 |
/usr/lib/gcc/x86_64- |
|||||||
.jcr |
0x0000000000401e48 |
0x8 |
/usr/lib/gcc/x86_64- |
把选项传给连接器 |
39 |
100个gcc小技巧
.dynamic |
0x0000000000401e50 |
0x190 |
|
|
|
|
||||
** dynamic |
0x0000000000401e50 |
0x190 |
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
.got |
0x0000000000401fe0 |
0x8 |
|
|
|
|
||||
** GOT |
0x0000000000401fe0 |
0x8 |
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
.got.plt |
0x0000000000401fe8 |
0x28 |
|
|
|
|
||||
** GOT PLT |
0x0000000000401fe8 |
0x28 |
|
|
|
|
||||
** GOT IRELATIVE PLT |
|
|
|
|
|
|
|
|||
|
|
0x0000000000402010 |
0x0 |
|
|
|
|
|||
** GOT |
0x0000000000402010 |
0x0 |
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
.data |
0x0000000000402010 |
0x10 |
|
|
|
|
||||
.data |
0x0000000000402010 |
0x4 |
/usr/lib/gcc/x86_64- |
|||||||
|
|
0x0000000000402010 |
|
data_start |
|
|
|
|||
|
|
0x0000000000402010 |
|
__data_start |
|
|||||
.data |
0x0000000000402014 |
0x0 |
/usr/lib/gcc/x86 |
|
||||||
_64- |
||||||||||
.data |
0x0000000000402018 |
0x8 |
/usr/lib/gcc/x86_64- |
|||||||
|
|
0x0000000000402018 |
|
__dso_handle |
|
|||||
.data |
0x0000000000402020 |
0x0 |
/tmp/ccBOhdmq.o |
|
|
|||||
.data |
0x0000000000402020 |
0x0 |
/usr/lib/x86_64 |
|||||||
.data |
0x0000000000402020 |
0x0 |
/usr/lib/gcc/x86_64- |
|||||||
.data |
0x0000000000402020 |
0x0 |
/usr/lib/gcc/x86_64- |
|||||||
|
|
|
|
|
|
|
|
|
|
|
.bss |
0x0000000000402020 |
0x10 |
|
|
|
|
||||
.bss |
0x0000000000402020 |
0x0 |
/usr/lib/gcc/x86_64- |
|||||||
.bss |
0x0000000000402020 |
0x0 |
/usr/lib/gcc/x86_64- |
|||||||
.bss |
0x0000000000402020 |
0x10 |
/usr/lib/gcc/x86_64- |
|||||||
.bss |
0x0000000000402030 |
0x0 |
/tmp/ccBOhdmq.o |
|
||||||
.bss |
0x0000000000402030 |
0x0 |
/usr/lib/x86_64 |
|||||||
.bss |
0x0000000000402030 |
0x0 |
/usr/lib/gcc/x86_64- |
|||||||
.bss |
0x0000000000402030 |
0x0 |
/usr/lib/gcc/x86_64- |
|||||||
|
|
|
|
|
|
|
|
|
|
|
.comment |
0x0000000000000000 |
0x2b |
|
|
|
|
||||
** merge strings |
|
|
|
|
|
|
|
|||
|
|
|
0x0000000000000000 |
0x2b |
|
|
|
|
||
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
||||||
** note header |
|
0x0000000000000000 |
0x1c |
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
0x0000000000000000 |
0x10 |
|
|
|
|
|||
** fill |
0x0000000000000010 |
0x9 |
|
|
|
|
||||
** zero fill |
0x0000000000000019 |
0x3 |
|
|
|
|
||||
|
|
|
|
|
|
|
||||
.symtab |
0x0000000000000000 |
0x390 |
|
|
|
|
||||
** symtab |
0x0000000000000000 |
0x390 |
|
|
|
|
||||
|
|
|
|
|
|
|
||||
.strtab |
0x0000000000000000 |
0x1d5 |
|
|
|
|
||||
** string table |
|
|
|
|
|
|
|
|
|
|
|
|
0x0000000000000000 |
0x1d5 |
|
|
|
|
|||
|
|
|
|
|
|
|
||||
.shstrtab |
0x0000000000000000 |
0x115 |
|
|
|
|
把选项传给连接器 |
40 |
100个gcc小技巧
设置动态连接器
技巧
有人问我,如何通过选项来指定动态连接器,而不使用缺省系统自带的动态连接 器。我后来查了下ld的手册,有这么一个选项:
Set the name of the dynamic linker. This is only meaningful wh
看起来,可以通过如下方式来完成:
$gcc foo.c
$ldd a.out
libc.so.6
注意,tmp目录下的动态连接器因为也是动态连接的,所以它本身是依赖系统缺省 的动态连接器。
贡献者
xmj
设置动态连接器 |
42 |
100个gcc小技巧
函数属性
函数属性 |
43 |
100个gcc小技巧
禁止函数被优化掉
例子
#if (GCC_VERSION > 4000)
#define DEBUG_FUNCTION __attribute__ ((__used__)) #define DEBUG_VARIABLE __attribute__ ((__used__)) #else
#define DEBUG_FUNCTION #define DEBUG_VARIABLE #endif
DEBUG_FUNCTION void debug_bb (basic_block bb)
{
dump_bb (bb, stderr, 0);
}
技巧
性__attribute__ ((__used__)) ,可以指定该函数是有用的,不能被优化掉。
贡献者
xmj
禁止函数被优化掉 |
44 |
100个gcc小技巧
#强制函数永远以inline的形式调用
例子
#if defined(__GNUC__)
#define FORCEDINLINE __attribute__((always_inline)) #else
#define FORCEDINLINE #endif
FORCEDINLINE int add(int a,int b)
{
return a+b;
}
技巧
性__attribute__ ((always_inline)) ,可以指定该函数永远以inline的形式调
用
贡献者
mengke
强制函数inline |
45 |
100个gcc小技巧
常见错误
常见错误 |
46 |
100个gcc小技巧
error: cast from ... to ... loses precision
例子
#include <iostream>
class Foo { public:
void print() const {
std::cout << (int)(this) << "\n";
}
};
int main()
{
class Foo foo;
foo.print(); return 0;
}
技巧
在g++编译上面的例子,会报如下错误:
$ g++ foo.cc
foo.cc: In member function ‘void Foo::print() const’:
foo.cc:6:28: error: cast from ‘const Foo*’ to ‘int’ loses precisio
这是一个强制类型转换的错误,你可以修改源代码为:
std::cout << (int*)(this) << "\n";
即可。
如果,你不想(或不能)去修改源程序,只是应为升级了gcc而带来了这样的错 误,那么也可以使用
error: cast from ... to ... loses precision |
47 |
100个gcc小技巧
$ g++ foo.cc
foo.cc: In member function ‘void Foo::print() const’:
foo.cc:6:28: warning: cast from ‘const Foo*’ to ‘int’ loses precis
贡献者
xmj
error: cast from ... to ... loses precision |
48 |
100个gcc小技巧
all warnings being treated as errors
技巧
在ubuntu系统下编译一个程序包,有时会遇到这样的错误:
$make
...
cc1: all warnings being treated as errors
这是因为缺省的CFLAGS里含有
$ make CFLAGS="...
贡献者
xmj
all warnings being treated as errors |
49 |
100个gcc小技巧
其它
其它 |
50 |
100个gcc小技巧
只做语法检查
例子
$cat foo.c union u {
char c; int i;
}
$gcc
foo.c:4:1: error: expected identifier or ‘(’ at end of input
技巧
如上所示,使用
贡献者
xmj
只做语法检查 |
51 |
100个gcc小技巧
保存临时文件
例子
$gcc
$ls foo.*
foo.c foo.i foo.o foo.s
$gcc
$ls a
foo foo.c foo.i foo.o foo.s
技巧
如上所示,使用选项
如果你在不同目录下有重名的源文件,那么中间文件就会有冲突了。此时,你可以 使用
贡献者
xmj
保存临时文件 |
52 |
100个gcc小技巧
打开警告信息
技巧
你的程序编译通过了,但并不意味着已经万事大吉,也许还存在一些不规范的地 方,或者一些错误隐患。建议,使用
$ gcc
贡献者
xmj
打开警告信息 |
53 |
100个gcc小技巧
指定语言类型
技巧
gcc是通过文件名后缀来判断源代码语言类型的。
如果你从标准输入把源码传给gcc,那么就需要通过
$echo "int x;" | gcc
$
.file
.comm
.ident
.section
贡献者
xmj
指定语言类型 |
54 |
100个gcc小技巧
改变结构体成员的字节对齐
例子
#include <stdio.h>
typedef struct
{
char a; int b;
} ST_A;
int main(void)
{
printf("sizeof(ST_A)=%ld\n",sizeof(ST_A));
}
技巧
在上面的程序里, ST_A 结构体的内存布局默认是这样的:
Offset |
1byte |
1byte |
1byte |
1byte |
|
|
|
|
|
0 |
a |
填充字节 |
填充字节 |
填充字节 |
|
|
|
|
|
4 |
b |
b |
b |
b |
|
|
|
|
|
编译执行,结果如下:
root@ubuntu:~$ gcc
使用gcc的"
样 ST_A 结构体中的成员 b 的地址将不再按照 4 字节对齐,内存布局变为:
Offset |
1byte |
1byte |
1byte |
1byte |
|
|
|
|
|
0 |
a |
填充字节 |
b |
b |
|
|
|
|
|
4 |
b |
b |
|
|
|
|
|
|
|
改变结构体成员的字节对齐 |
55 |
100个gcc小技巧
编译执行,结果如下:
root@ubuntu:~$ gcc
sizeof(ST_A)=6
当不指定“ n ”时,将没有填充字节,所有成员将一个挨着一个排在一起:
Offset |
1byte |
1byte |
1byte |
1byte |
|
|
|
|
|
0 |
a |
b |
b |
b |
|
|
|
|
|
4 |
b |
|
|
|
|
|
|
|
|
编译执行,结果如下:
root@ubuntu:~$ gcc
sizeof(ST_A)=5
由于这个编译选项会导致ABI(Application Binary Interface)的改变,所以使用时一 定要谨慎。 详情参见gcc手册
贡献者
nanxiao
改变结构体成员的字节对齐 |
56 |