Red Hat Training

A Red Hat training course is available for RHEL 8

第 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 选项来检查 control-flow 指令的目标地址来提高程序安全性。
  • 新的 -Wstringop-truncation 警告选项列出了对绑定字符串操作功能的调用,如 strncatstrncpystpncpy,它们可能会截断复制的字符串或者使目的地保持不变。
  • -Warray-bounds 警告选项已被改进来更好地检测边界外数组索引和指针偏移。
  • 添加了 -Wclass-memaccess 警告选项,以警告使用原始内存访问功能(如 memcpyrealloc )对非特权类的对象可能会不安全的操作。

构架和处理器支持

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

  • 添加了多个适用于 Intel AVX-512 架构、微架构和 Intel Software Guard 扩展(SGX)的新架构特定选项。
  • 现在,代码生成可以针对 64 位 ARM 架构 LSE 扩展、ARMv8.2-A 16 位 Floating-Point 扩展(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++11 auto 关键字功能的子集。
  • 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 的安全性增强

本节详细介绍了在 Red Hat Enterprise Linux 7.0 发行版本后,GCC 中与安全性相关的变化。

新警告

添加了这些警告选项:

选项显示警告信息

-Wstringop-truncation

对绑定字符串操作功能的调用,如 strncatstrncpystpncpy,这些功能可能会截断复制的字符串,或者使目的地保持不变。

-Wclass-memaccess

原始内存功能(如 memcpyrealloc )可能会以不安全的方式操作非特权类对象。

该警告有助于检测以下调用:绕过用户定义的构造器或复制分配运算符、损坏的虚拟表指针、符合条件的类型或引用的数据成员或成员指针。该警告还会检测到可绕过数据成员的访问控制的调用。

-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 系列调用时可能会出现特定和可能的缓冲溢出。有关 level 值的详情和说明,请参阅 gcc(1) 手册页。

-Wformat-truncation=level

对格式化输出功能的 snprintf 系列调用的特定和可能的输出截断。有关 level 值的详情和说明,请参阅 gcc(1) 手册页。

-Wstringop-overflow=type

对字符串处理功能(如 memcpystrcpy )调用的缓冲溢出。有关 level 值的详情和说明,请参阅 gcc(1) 手册页。

警告改进

改进了以下 GCC 警告:

  • -Warray-bounds 选项已被改进来检测更多对边界外数组索引和指针偏移的实例。例如,检测到将负或过多索引到灵活的数组成员和字符串字面上。
  • GCC 7 中引入的 -Wrestrict 选项已被改进,通过对标准内存和字符串操作功能(如 memcpystrcpy )的限制限定参数来检测更多对对象的重叠访问实例。
  • -Wnonnull 选项已被改进,可检测一组更广泛的将 null pointers 传递给预期使用非空参数的函数的情况(使用属性 nonnull解析)。

新的 UndefinedBehaviorSanitizer

添加了一个新的用于检测未定义行为的运行时清理程序,称为 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 前缀的内置无效参数。包括来自 -fsanitize=undefined 的检查。

-fsanitize=pointer-overflow

为指针嵌套执行 cheap run-time 测试。包括来自 -fsanitize=undefined 的检查。

AddressSanitizer 的新选项

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

选项检查

-fsanitize=pointer-compare

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

-fsanitize=pointer-subtract

关于减去指向不同内存对象的指针的警告。

-fsanitize-address-use-after-scope

清除其地址的变量,并在定义了 变量的范围之后使用变量。

其他清理程序和工具

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

其他资源

  • 有关向上述某些选项提供的值的详情和说明,请参阅 gcc(1) 手册页:

    $ man gcc

16.1.3. RHEL 8 中 GCC 中的兼容性破坏变化

std::string 和 中的 C++ ABI 更改 std::list

libstdc++ 库中的 std::stringstd::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++ 代码

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

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