第 16 章 编译器和开发工具
16.1. RHEL 7 后对 toolchain 的更改
以下小节列出了自 Red Hat Enterprise Linux 7 中描述组件发行版本起的更改。另请参阅 Red Hat Enterprise Linux 8.0 发行注记。
16.1.1. RHEL 8 中的 GCC 的更改
在 Red Hat Enterprise Linux 8 中,GCC 工具链基于 GCC 8.2 发行系列。从 Red Hat Enterprise Linux 7 开始的显著变化包括:
- 添加了大量常规优化,如别名分析、向量器改进、相同的代码折叠、流程间分析、存储合并优化传递等。
- 改进了 Address Sanitizer。
- 添加了用来检测内存泄漏的 Leak Sanitizer。
- 添加了用于检测未定义行为的 Undefined Behavior Sanitizer。
- 现在可使用 DWARF5 格式生成调试信息。这个功能是实验性的。
- 源代码覆盖分析工具 GCOV 已进行了各种改进。
- 添加了对 OpenMP 4.5 规格的支持。此外,C、C++ 和 Fortran 编译器现在支持 OpenMP 4.0 规范的卸载功能。
- 静态检测某些可能的编程错误的新警告和改进诊断已添加。
- 现在,源位置作为范围而不是点来跟踪,这样允许更丰富的诊断。编译器现在提供"fix-it"提示,建议可能的代码修改。添加了拼写检查器以提供替代名称,并更容易地检测拼写错误。
Security
GCC 已被扩展,提供一些工具以确保增加生成的代码的强化。与安全相关的改进包括:
-
为带有溢出检查的算术添加了
__builtin_add_overflow
、__builtin_sub_overflow
和__builtin_mul_overflow
内置函数。 -
添加了
-fstack-clash-protection 选项
,以生成防止堆栈冲突的额外代码。 -
引入了
-fcf-protection 选项
,来检查控制流指令的目标地址,以提高程序的安全性。 -
新的
-Wstringop-truncation
警告选项列出了对绑定字符串操作函数的调用,如strncat
、strncpy
或stpncpy
,它们可能会截断复制的字符串,或者让目的地保持不变。 -
改进了
-Warray-bounds
警告选项,以更好地检测超出边界的数组索引和指针偏移。 -
添加了
-Wclass-memaccess
警告选项,以警告原始内存访问函数(如memcpy
或realloc
)对非平凡类对象可能的不安全操作。
构架和处理器支持
架构和处理器支持的改进包括:
- 为 Intel AVX-512 架构、一些微架构和 Intel 软件保护扩展(SGX)添加了多个特定于架构的新选项。
- 现在,代码生成可以针对 64 位 ARM 架构 LSE 扩展、ARMv8.2-A 16 位浮点扩展(FPE)以及 ARMv8.2-A、ARMv8.3-A 和 ARMv8.4-A 架构版本。
-
ARM 和 64 位 ARM 架构上的
-march=native
选项的处理已被修复。 - 添加了对 64 位 IBM Z 架构的 z13 和 z14 处理器的支持。
语言和标准
与语言和标准有关的显著变化包括:
- C 语言编译代码时使用的默认标准已改为使用 GNU 扩展的 C17。
- C++ 语言编译代码时使用的默认标准已改为使用 GNU 扩展的 C++14。
- C++ 运行时程序库现在支持 C++11 和 C++14 标准。
-
C++ 编译器现在实现了具有许多新功能的 C++14 标准,如变量模板、非静态数据成员初始化器的聚合、扩展的
constexpr
指定符 、了调整大小的释放函数、通用 lambdas、可变长度数组、数字分隔符等。 - 改进了对 C 语言标准 C11 的支持:现在提供了 ISO C11 atomics、通用选择和线程存储。
-
新的
__auto_type
GNU C 扩展在 C 语言中提供了 C++11auto
关键字的功能子集。 -
由 ISO/IEC TS 18661-3:2015 标准指定的
_FloatN
和_FloatNx
类型名称现在由 C 前端识别。 -
C 语言编译代码时使用的默认标准已改为使用 GNU 扩展的 C17。这与使用
--std=gnu17
选项具有同样的效果。在以前的版本中,默认值是带有 GNU 扩展的 C89。 - GCC 现在可以使用 C++17 语言标准以及 C++20 标准中的某些功能对代码进行实验性编译。
- 现在,传递空类作为参数不包括在 Intel 64 和 AMD64 构架中,如平台 ABI 要求。传递或返回仅带有删除副本和移动构造器的类,现在使用与带有非平凡副本或移动构造器的类相同的调用约定。
-
C++11
alignof
运算符返回的值已被修正,以匹配 C_Alignof
运算符,并返回最小对齐。要查找首选的对齐,请使用 GNU 扩展名__alignof__
。 -
Fortran 语言代码的
libgfortran
库的主版本已变为 5。 - 对 Ada(GNAT)、GCC Go 和 Objective C/C++ 语言的支持已删除。使用 Go Toolset 进行 Go 代码开发。
其它资源
16.1.2. RHEL 8 中 GCC 的安全性增强
以下是 GCC 中与安全性相关的更改,以及自 Red Hat Enterprise Linux 7.0 发行版本之后添加的更改。
新警告
添加了这些警告选项:
选项 | 显示警告信息 |
---|---|
|
对绑定的字符串操作函数(如 |
|
原始功能(如 警告帮助检测以下调用:绕过用户定义的构造器或复制-分配运算符、损坏的虚拟表指针、常量限定类型的数据成员或引用或成员指针。该警告还会检测到可绕过数据成员的访问控制的调用。 |
| 代码缩进对于阅读代码的人可能会造成对代码块结构的误导。 |
|
调用内存分配超过 size 的内存分配功能。还可与通过两个参数相乘指定分配的函数一起工作,以及与使用属性 |
|
调用内存分配功能,试图分配零内存。还可与通过两个参数相乘指定分配的函数一起工作,以及与使用属性 |
|
所有对 |
|
请求内存大于 size 时调用 |
| 可超过指定大小或者其绑定未知约束的 Variable Length Arrays(VLA)定义。 |
|
在调用格式化输出函数 |
|
在调用格式化输出函数的 |
|
在调用字符串处理函数(如 |
警告改进
改进了以下 GCC 警告:
-
改进了
-Warray-bounds
选项,以检测更多超出边界数组索引和指针偏移的实例。例如,检测到灵活的数组成员和字符串字面值的负或过量索引。 -
GCC 7 中引入的
-Wrestrict
选项已被改进,以检测通过对标准内存和字符串操作函数(如memcpy
和strcpy
)的限制限定参数重叠访问对象的更多实例。 -
-Wnonnull
选项已改进,以检测一组将空指针传给预期非空参数(使用属性nonnull
装饰)的函数的更广泛的情况。
新的 UndefinedBehaviorSanitizer
添加了一个新的用于检测未定义行为的运行时清理程序,称为 UndefinedBehaviorSanitizer。以下选项需要加以注意:
选项 | 检查 |
---|---|
| 检查浮点被被零除。 |
| 检查浮点类型到整数转换的结果是否溢出。 |
| 启用阵列绑定控制并检测对边界外的访问。 |
| 启用协调检查并检测各种没有对齐的对象。 |
| 启用对象大小检查并检测到各种对边界外的访问。 |
| 启用对 C++ 成员功能调用、成员访问以及指针到基本类别和派生类之间的一些转换。另外,检测引用的对象没有正确的动态类型。 |
|
启用对阵列绑定的严格的检查。这启用了 |
| 即使在使用通用向量的诊断操作中诊断异常溢出。 |
|
在运行时诊断 |
|
为指针嵌套执行 cheap run-time 测试。包括 |
AddressSanitizer 的新选项
这些选项已经被添加到 AddressSanitizer 中:
选项 | 检查 |
---|---|
| 指向不同内存对象的指针的警告。 |
| 关于指向不同内存对象的指针的减法的警告。 |
| 清除在定义了变量的作用域之后获取和使用其地址的变量。 |
其他清理程序和工具
-
添加了
-fstack-clash-protection
选项,以便在堆栈空间被静态或动态分配时插入探测,以可靠地检测堆栈溢出,从而减轻依赖于跳过操作系统提供的堆栈保护页的攻击向量。 -
添加了一个新的选项
-fcf-protection=[full|branch|return|none]
,以通过检查控制流传输指令的目标地址(如间接函数调用、函数返回、间接跳转)是否有效,来执行代码插入并提高程序安全性。
其它资源
有关提供给上述某些选项的值的详情和说明,请参阅 gcc(1) 手册页:
$ man gcc
16.1.3. RHEL 8 中 GCC 兼容性破坏的变化
std::string
和 std::list
中 C++ ABI 的更改
libstdc++
库中的 std::string
和 std::list
类的应用二进制接口(ABI)在 RHEL 7 (GCC 4.8) 和 RHEL 8(GCC 8)之间发生了变化,以符合 C++11 标准。libstdc++
库支持新的和旧的 ABI,但其他一些 C++ 系统库则不支持。因此,库动态链接这些库的应用程序需要重建。这会影响所有 C++ 标准模式,包括 C++98。它还影响了使用 RHEL 7 的红帽开发人员工具集编译器构建的应用程序,该编译器保留旧的 ABI,以保持与系统库的兼容性。
GCC 不再构建 Ada、Go 和 Objective C/C++ 代码
在 Ada(GNAT)、GCC Go 和 Objective C/C++ 语言中构建代码的能力已从 GCC 编译器中删除。
要构建 Go 代码,请使用 Go Toolset。