GNU C Compiler在1987年3月22日发布了第一个beta版本,Richard Stallman原本想利用Free University Compiler Kit,但作者Andy Tanenbaum不想免费提供,RMS因此决定GNU的首个项目将是编译器。GCC是基于一个现有的Pastel编译器,使其扩展支持编译C,后用C进行重写。
代码:
git clone git://gcc.gnu.org/git/gcc.git
http://www.hellogcc.org/
一个有关GCC和GDB的博客。其中的大牛teawater(朱辉)开发了一个Linux动态跟踪器KGTP,他的blog:
http://teawater.github.io/
https://www.cnblogs.com/kuoAT/p/9590606.html
深入分析GCC(王亚刚 著)
GNU Binutils是一系列二进制工具的集合。
https://www.zhihu.com/answer/2258430030
GNU Binutils工具集介绍
1、预处理,生成.i的文件(预处理器cpp)
2、将预处理后的文件转换成汇编语言,生成文件.s(编译器egcs)
3、有汇编变为目标代码(机器代码)生成.o的文件(汇编器as)
4、连接目标代码,生成可执行程序(链接器ld)
常见的Linker主要有:GNU的Gold、LLVM的LLD,以及最新的Mold。
mold(A Modern Linker)大大改进了相关算法的并行性,因此性能要比前两者快得多。
理论上gcc做链接和ld做链接,应该是一样的效果,然而实际情况要复杂一些。有的厂商的工具链会给gcc添加一些环境变量之类的私货,所以两者的行为就变的很有差异了。遇到这种问题,互换是一种好的解决问题的思路。
有的链接器对链接顺序有要求,一般按照c代码、自定义库、标准库的顺序来链接,也就是越基础底层的库,越在后面。(这个顺序正好和声明的顺序相反)
gcc -c ./sparse_matrix.c -o sparse_matrix.o -luserlib -lm
但是如果有一系列很底层的库,他们太底层了,以至于会出现相互依赖的情况(circular dependence),那gcc提供了一个option很好的解决了这个情况:
-Wl,--start-group -lmy_lib -lyour_lib -lhis_lib -Wl,--end-group
再比如下面的例子:
https://github.com/antkillerfarm/antkillerfarm_crazy/tree/master/helloworld/linux_so
gcc -o main_link main_link.c -L. -lhello
这条命令中的main_link.c如果放到-lhello
之后就会出问题。也考虑使用--start-group
和--end-group
之类的链接选项解决链接顺序问题。
https://stackoverflow.com/questions/27475977/c-undefined-reference-to-sqrt-even-with-lm
C - undefined reference to “sqrt” even with ‘-lm’
https://mp.weixin.qq.com/s/TnqAqpmuXsGFfpcSUqZ9GQ
今日头条优化实践:iOS包大小二进制优化,一行代码减少60MB下载大小
https://zhuanlan.zhihu.com/p/145263213
谈谈程序链接及分段那些事
有的时候会遇到-Werror=XXXX
这样的编译错误,如果确实不想改代码的话,可以用-Wno-error=XXXX
或者-Wno-XXXX
来回避之。
查看当前版本gcc编译器开了哪些编译优化,使用命令:
gcc/g++ -Q -O2 --help=optimizers
查看向量优化信息:
g++ -fopt-info-vec-optimized main.cpp -O3
优化选项开关:
以-ftree-loop-vectorize
为例,-f
表示打开某选项,改成-fno-
前缀就是关闭。
https://mp.weixin.qq.com/s/asjPNb_SXF5guNIcdduHmQ
从一个crash问题展开,探索gcc编译优化
这两个命令都可以查看可执行文件的符号表。
示例:
nm XXX.so
readelf -h XXX.so
这两个命令虽然很早就在gcc工具链中了,但是早期版本只能查看本工具链编译的可执行文件。现在的话,主流的CPU指令集都可以支持了,不必采用arm-readelf
这样的特殊前缀版本了。
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 40
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 50
sudo update-alternatives --config gcc
make -j 4
可用nproc
命令动态获取编译机的CPU核数。
利用Distcc和Dmucs构建大规模、分布式C++编译环境。
PCH(Precompiled Header)
CCache(Compiler Cache)是一个编译缓存工具,其原理是将cpp的编译结果保存在文件缓存中,以后编译时若对应文件无变动可直接从缓存中获取编译结果。需要注意的是,Make本身也有一定缓存功能,当目标文件已编译(且依赖无变化)时,若源文件时间戳无变化也不会再次编译;但CCache是按文件内容做的缓存,且同一机器的多个项目可以共享缓存,因此适用面更大。
C++20之前的版本会把每一个cpp当做一个编译单元处理,会存在引入的头文件被多次解析编译的问题。而Module的出现就是解决这一问题。
Google推出了开源的Include-What-You-Use工具(简称IWYU),使用该工具可以扫描出文件依赖问题,同时该工具还提供脚本解决头文件依赖问题。
https://mp.weixin.qq.com/s/yITNjo_UQi8-OKQNOfGrPw
C++服务编译耗时优化原理及实践
设置参数:
启动时:
gdb --args <exe> <arg1> ...
这里把可执行程序当作arg0,参数当作arg1…
运行时:
set args -l
INT3指令—又叫断点指令,是软件断点的实现基础。
标志寄存器FLAGS的TF标志—陷阱标志位。是单步执行的实现基础。
断点地址寄存器DR0一DR3—用于设置断点地址(线性内存地址或l/O地址),是硬件断点的实现基础。
断点控制寄存器DR7—用来控制和进一步描述四个调试地址寄存器(DR0一DR3)的断点条件。
断点状态寄存器DR6—当断点发生时,向调试器报告该断点的具体情况,以便调试器区分发生的是哪个断点。
断点异常(#BP)一当INT3指令执行时,会导致此异常,CPU转到该异常的处理程序。
调试异常(#DB)一当除INT3指令以外的调试事件发生时会导致此异常。
任务状态段(TS)S的T标志任务陷阱标志,当切换到设置了T标志的任务时,中断到调试器。
分支记录机制用来记录上一个分支、中断和异常的地址等信息。
https://zhuanlan.zhihu.com/p/608919072
为脚本开发调试器
参考:
https://mp.weixin.qq.com/s/30Zh_8H6QfDgJuG9e9ORSQ
使用gdb调试多进程程序
https://zhuanlan.zhihu.com/p/254879649
GDB的那些奇淫技巧
https://mp.weixin.qq.com/s/y3c07Hk7g3P-rd0oDzszlA
GDB底层实现原理
https://zhuanlan.zhihu.com/p/678879367
GDB高级技巧:Linux多线程调试没那么难,可别再用printf了
逆向调试,不是逆向工程的逆向,而是在debug的时候,需要退回到过去,比如还想再看看这个函数是如何计算的,但是又不想重新启动程序,或者重新复现。这里的退回到过去,就是逆向。
gdb提供的reverse debugging比较原始,需要长时间使用才能熟练。rr: record, Replay就是一大杀器,它由Mozilla开发。
官网:
https://rr-project.org/
参考:
https://zhuanlan.zhihu.com/p/364075104
又一debug装逼技能:record, replay
Hex0:起点,Binary不超过1KB,用来从带注释的hex dump生成binary。
Hex1、Hex2:Hex0+偏移量计算,用来简化后续过程;每一级由上一级实现和编译。
M0:宏汇编器,由Hex2实现和编译。
cc_*:用汇编写的C子集编译器(支持x86、x644、ARMv7和v8);由M0编译。
M2-Planet + mescc-tools:用先前的C子集制作的用于生成Mes的基础工具。
Mes + MesCC -> 一个修改过的TCC -> GCC 4.7 -> 现代的GCC
https://www.zhihu.com/question/441129390
假如有某种力量使得世界上所有编译器都被删除了,人类是否需要从打孔卡开始写第一个编译器?
https://zhuanlan.zhihu.com/p/693132914
计算机考古:第一代C语言编译器
C4:4个函数实现的C语言编译器
https://github.com/rswier/c4
https://zhuanlan.zhihu.com/p/672720180
用4个函数528行代码写了个能自举的C编译器!
查看glibc版本:
ldd --version
代码中获得glibc版本:
#if defined(__GLIBC__) && __GLIBC_MINOR__ >= 33 // for glibc 2.33+
...
#endif
社区用例主要是编译器开发过程中出错小程序的积累,因此也称之为regressiontest,回归测试用例,gcc社区的dejagnu有将近8万个用例。
https://zhuanlan.zhihu.com/p/37594930
编译器是如何做测试的
https://github.com/Bill-Haku/kawaii-gcc/
一个修改gcc编译出错信息文本的项目
https://zhuanlan.zhihu.com/p/372526494
GCC的整体架构
https://www.zhihu.com/question/478761697
gcc -O3
具体做了些什么事情?
您的打赏,是对我的鼓励