-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathgcc_gdb.txt
84 lines (61 loc) · 5.38 KB
/
gcc_gdb.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// gcc & gdb related
1、在查看coredump文件时,如果遇到调用栈栈顶附近的函数为 ??,则可能是
栈被破坏了,调查的一个方向是 f 0 ,p $rsp 查看第一层函数栈顶指针,
再 f $top , p $rsp 查看调用栈栈顶的栈指针,两者相减,看是否是调用栈
过深导致。
2、上述过程中,不能使用rbp寄存器,因为使用 -fomit-frame-pointer 选项编译时,
会去掉rbp寄存器的使用
3、gcc 4.x及以下的版本的 string实现是基于引用计数和 COW,gcc 5.x 替换了另一种短字符优化sso的方案,
其实现就是string分配16字节的预留空间,和allocated_capacity保存在一个union中。
4、gcc的-l选项只在编译时起作用,如果是静态库,那么因为已经打包进入binary,运行时无需特殊指定库路径,
如果是动态库,那么gcc会在默认路径下找库,和编译时库路径无关。
LD_LIBRARY_PATH环境变量就是指定运行时库路径的。
编译时可以通过 -W,--rpath 来指定运行时的动态库路径
5、gcc在使用静态库时,不会把整个库都打包进去,而是会分析调用链,按需加载使用,减小binary大小
6、想查看gcc默认的搜索头文件路径,可以在编译时加上 --verbose选项
7、/lib64/ld-linux-x86-64.so.2 这个文件是linux默认的 dynamic-linker,在命令行执行 chmod 等程序时,
系统其实执行的是 /lib64/ld-linux-x86-64.so.2 chmod,它的作用是完成动态库的加载,然后执行ELF程序
所以可以测试一个binary 没有 可执行权限,然后由 /lib64/ld-linux-x86-64.so.2 binary 也是可以启动的
8、为什么编译时不需要显示的指定 glibc的库
glibc库的路径已经固化到gcc中了,不用再显示指定,除非要用自己的glibc库
9、gcc编译出来的C库,不能直接在g++编译的C++程序中使用,如果使用,需要在对应的header文件中添加 extern "C" 标识,
但是C中没有extern "C" 的写法,所以,需要在程序中使用预编译宏来判断,例如 #ifdef __cplusplus
10、在实现用户态的spin_lock时,建议使用CPU的 pause 指令,这可以提高在 spin wait场景下的性能
具体可以参考网上文章的说明和Nginx的spin lock实现
11、在使用glibc等库中的函数时,如果不确定,一定要先man一下,看看应该引用哪些头文件,
如果没用正确的引用头文件,会引入奇怪的问题,例如调用 strerror core,
lseek 函数偏移量异常等。
strerror core的原因是,编译器将函数返回值转为int,而64位环境下指针为8bytes,int为4bytes,访存异常。
lseek这个是因为,如果第二个参数显示的写为字面值,编译器传参为 int,但是函数中用的是 8bytes的数据,
会引入一些非预期数据,导致seek结果非预期。
12、高版本中的gdb可以直接查看vector中的数据,在较低版本中,需要 *(vector.M_impl.M_start)@vector.size()
这种方法来看 vector 全部内容
13、gcc -M test.c 选项可以看到编译时所有include的头文件
gcc -MM选项是过滤了系统头文件之后的输出
14、在用GDB跟踪某些binary时,step比较慢,可以在GDB的命令行中 set env LD_BIND_NOW=true来解决
15、在用GDB attach 进程时,可以使用 info sharedlibrary 命令来查看当前加载动态链接库的情况,
同时也可以使用sharedlibrary 命令来手动加载某些库
16、GDB调试C++程序时,如果定位到this指针的位置,那么可以使用 x /10a 命令来查看虚表的内容
方便定位问题
17、gcc可以编译.cpp文件,但是会遇到 undefined reference 的报错,这是因为没有链接C++的
stdc++ 库,只要在编译cpp文件时,加上 -lstdc++ 选项,则编译可以正常进行。
同时,编译分为如下几步
cc1 / cc1plus (编译) --> as (汇编) --> collect2 () --> ld (链接)
18、gcc工具编译链接时(具体是ld工具)查找符号的顺序是从左到右,且.a 或 .o 文件只会被处理一次;
所以被依赖的库需要放在右边,而项目.o文件需要放在靠左边的位置;
或者同一库文件,多写几次 -l;
动态链接库就没有这个问题
19、使用 LD_DEBUG 环境变量可以查看可执行文件的链接库/符号查找细节。常用命令如下:
LD_DEBUG=symbols,files $COMMAND
LD_DEBUG环境变量本身支持的取值可以通过 LD_DEBUG=help cat 查看。
20、可以通过 cat /proc/${pid}/maps | grep so 的方式来查看进程运行时都加载了哪些so
21、可以通过如下命令获取进程中各个线程栈
gdb <binary> -c <coredump> -ex "thread apply all bt" -ex "quit" > output.log
如果运行的进程是个nostripped版本,也可以尝试使用pstack来抓栈
22、jump *0x1234 可以做到调到地址为 0x1234地址的指令处;
这个指令会忽略中间跳过的代码
23、在x86架构下进程core 原因为 illegal instruction时,不能忽略,可以gdb disass 看下当前执行到
哪条指令报的错,再然后可以去查对应cpu型号是否支持这个指令
这两天就遇到一些较老型号的CPU不支持vinsert128 这个指令导致UT core;vinsert128 是avx2指令集中的一个
可以 lscpu | grep -i avx2 看对应cpu是否支持
谨记,不可大意,还是可以尝试去定位下