第 16 章 编译器和开发工具

16.1. RHEL 7 后的工具链更改

以下小节列出了从 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 规格的支持。另外,OpenMP 4.0 规格的卸载功能现由 C、C++ 和 Fortran 编译器支持。
  • 增加了新的警告以及改进的诊断工具,用于对 一 些可能编程的错误进行静态检测。
  • 源位置现在作为范围而不是点进行跟踪,这样可以进行更丰富的诊断。编译器现在提供 "fix-it" 提示,可能进行代码修改。添加了 一 个拼写检查器,以提供其他名称并方便地检测拼写错误。

Security

GCC 已经扩展,提供 一 些工具,以确保进 一 步强化生成的代码。与安全性有关的改进包括:

  • 带有溢出检查的 arithmetics 的 __builtin_add_overflow, __builtin_sub_overflow, 和 __builtin_mul_overflow 的内建功能。
  • 添加了 -fstack-clash-protection 选项来针对堆栈冲突生成额外的代码保护。
  • 引进了 -fcf-protection 选项来检查 control-flow 指令的目标地址以便提高程序安全性。
  • 新的 -Wstringop-truncation 警告选项列出对绑定字符串操作函数的调用,如 strncat, strncpy, 或 stpncpy,它们可能会截断 复制的字符串或使目的地不更改。
  • 改进了 -Warray-bounds 警告选项,以更好地检测出站外阵列索引和指针误差。
  • 添加了 -Wclass-memaccess 警告选项来警告,根据原始内存访问功能(如 memcpyrealloc)对非延迟类类型的对象进行潜在的不安全操作。

构架和处理器支持

架构和处理器支持的改进包括:

  • 为 Intel AVX-512 构架添加了多个新的架构选项,并添加了 一 些微架构以及 Intel 软件卫士扩展(SGX)。
  • 代码的生成可以针对 64 位 ARM 架构 LSE 扩展, ARMv8.2-A 16-bit Floating-Point 扩展(FPE)以及 ARMv8.2-A、ARMv8.3-A 和 ARMv8.4-A 架构版本。
  • ARM 和 64 位 ARM 架构中的 -march=native 选项的处理已被修复。
  • 添加了对 IBM Z 架构的 z13 和 z14 处理器的支持。

语言和标准

与语言和标准有关的显著变化包括:

  • 在编译 C 语言代码时使用的默认标准已改为 C17,并附带 GNU 扩展。
  • 在编译 C++ 语言的代码时使用的默认标准已改为 C++14并附带 GNU 扩展。
  • C++ 运行时程序库现在支持 C++11 和 C++14 标准。
  • C++ 编译器现采用 C++14 标准,它包含很多新特性,如变量模板、非静态数据成员初始化器聚合、扩展的 constexpr 指定器、有大小限制的取消分配功能、通用的 lambdas、长度可变的阵列、数字分隔器等。
  • 改进了对 C 语言标准 C11 的支持: ISO C11 Atomics、通用选择和线程本地存储现在可用。
  • 新的 __auto_type GNU C 扩展提供 C++11 auto 关键字在 C 语言中的子集。
  • 由 ISO/IEC TS 18661-3:2015 标准指定的 _FloatN_FloatNx 类型名称现在由 C 前端识别。
  • 在编译 C 语言代码时使用的默认标准已改为 C17,并附带 GNU 扩展。这和 --std=gnu17 选项的作用相同。在以前的版本中,默认为 C89 和 GNU 扩展。
  • GCC 现在可以使用 C++17 语言标准以及 C++20 标准的某些特性,通过实验性编译代码。
  • 根据平台 ABI 的要求,将空类作为参数传递现在在 Intel 64 和 AMD64 构架中不会占用空间。传递或返回 一 个只删除的复制和移动构造函数的类,现在使用和类具有非原始拷贝或移动构造函数相同的调用约定。
  • 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 发布后添加。

新警告

添加了这些警告选项:

选项显示的警告

-Wstringop-truncation

调用绑定的字符串操作功能,比如 strncatstrncpystpncpy,它们可能截断复制的字符串,或者使目的地不更改。

-Wclass-memaccess

原始功能(如 memcpyrealloc)可能会以不安全的方式处理类型为非 trivial 类的对象。

该警告可帮助探测绕过用户定义的构造器或复制操作符、破坏虚拟表指针、相同类型或参考的数据成员或者成员指针的调用。这个警告还会检测到绕过对数据成员的访问控制的调用。

-Wmisleading-indentation

代码缩进对于阅读代码的人可能会造成对代码块结构的误导。

-Walloc-size-larger-than=size

当分配的内存量超过其 size,调用内存分配功能。还可以使用通过乘两个参数和用属性 alloc_size 分开来指定分配的功能。

-Walloc-zero

调用内存分配功能,试图分配零内存。还可以使用通过乘两个参数和用属性 alloc_size 分开来指定分配的功能。

-Walloca

所有对 alloca 功能的调。

-Walloca-larger-than=size

请求内存大于 size 时调用 alloca 功能。

-Wvla-larger-than=size

可超过指定大小或者其绑定未知约束的 Variable Length Arrays(VLA)定义。

-Wformat-overflow=level

对格式化输出函数的 sprintf 系列调用的特定和可能的缓冲区溢出。有关 等级 值的详情和解释,请参见 gcc(1) 手册页。

-Wformat-truncation=level

在调用格式化输出函数的 snprintf 线时, 指定 和可能输出截断。有关 等级 值的详情和解释,请参见 gcc(1) 手册页。

-Wstringop-overflow=type

对字符串处理功能(如 memcpystrcpy)的调用缓冲溢出。有关 等级 值的详情和解释,请参见 gcc(1) 手册页。

警告改进

这些 GCC 警告已改进:

  • 改进了 -Warray-bounds 选项来检测更多非绑定阵列索引和指针误差的实例。例如,探测到灵活的数组成员以及字符串字面量的负数或过度索引。
  • GCC 7 引入的 -Wrestrict 选项通过对标准内存和字符串操作功能(如 memcpystrcpy)具有限制的限定参数来检测更多对象被重复访问的实例。
  • 改进了 -Wnonnull 选项,可检测到一组更多的情况,将空指符传递给预期为非空参数的函数(通过属性 nonnull 进行检查)。

新的 UndefinedBehaviorSanitizer

添加了 一 个新的运行时 sanitizer,用于检测 UndefinedBehaviorSanitizer 未定义的行为。以下选项需要加以注意:

选项检查

-fsanitize=float-divide-by-zero

检查浮点被被零除。

-fsanitize=float-cast-overflow

检查浮点类型到整数转换的结果是否溢出。

-fsanitize=bounds

启用阵列绑定控制并检测对边界外的访问。

-fsanitize=alignment

启用协调检查并检测各种没有对齐的对象。

-fsanitize=object-size

启用对象大小检查并检测到各种对边界外的访问。

-fsanitize=vptr

允许检查 C++ 成员功能调用、成员访问以及 一 些指针到基本和衍生类之间的转换。另外,当被引用的对象没有正确的动态类型时,检测到被引用的对象何时没有正确的动态类型。

-fsanitize=bounds-strict

启用对阵列绑定的严格检查。这会启用 -fsanitize=bounds 并工具化灵活的阵列类型阵列。

-fsanitize=signed-integer-overflow

诊断算数溢出,即使在带有普通向量的计算操作中也是如此。

-fsanitize=builtin

在运行时诊断 __builtin_clz__builtin_ctz 前缀的 builtins 的参数。包括 -fsanitize=undefined=undefined 的检查。

-fsanitize=pointer-overflow

为指针打包执行简单的运行时测试。包括 -fsanitize=undefined=undefined 的检查。

AddressSanitizer 的新选项

这些选项已经被添加到 AddressSanitizer 中:

选项检查

-fsanitize=pointer-compare

指向不同内存对象的指针的警告。

-fsanitize=pointer-subtract

指向不同内存对象的指针的减小的警告。

-fsanitize-address-use-after-scope

检查并清理在定义了变量的范围后获取并使用的变量。

其他清理程序和工具

  • 当堆栈空间被静态分配或动态地探测堆栈溢出时,添加了 -fstack-clash-protections 选项来插入探测,从而减轻依赖于操作系统提供的堆栈保护页面跳过的攻击。
  • 增加了一个新的选项 -fcf-protection=[full branch return none] 来执行代码增强,并通过检查 control-flow 传输指令(如间接功能调用、功能返回、间接跳过)的目标地址来提高程序安全性。

其它资源

  • 关于向以上选项提供的数值的更多详情和解释,请参见 gcc(1) 手册页:

    $ man gcc

16.1.3. 在 RHEL 8 中 GCC 的兼容性更改

std::stringstd::list 中 C++ ABI 的更改

来自于 libstdc++ 库的 std::stringstd::list 类的 Application Binary Interface (ABI) 已在 RHEL 7 (GCC 4.8) 和 RHEL 8 (GCC 8) 间有变化来使用 C++11 标准。libstdc++ 库支持旧的和新的 ABI,但其他一些 C++ 系统库则不支持。因此,需要重建动态链接到这些库的应用程序。这会影响所有 C++ 标准模式,包括 C++98。它还会影响到在 RHEL 7 中由 Red Hat Developer Toolset 编译程序构建的应用程序,该编译程序会保留旧的 ABI 以保持与系统库的兼容性。

GCC 不再构建 Ada、Go 和 Objective C/C++ 代码

GCC 编译器删除了在 Ada(GNAT)、GCC Go 和 Objective C/C++ 语言中构建代码的能力。

要构建 Go 代码,请使用 Go Toolset。


为了尽快向用户提供最新的信息,本文档可能会包括由机器自动从英文原文翻译的内容。如需更多信息,请参阅此说明。