在 Linux 内核中探索 GNU 扩展

主要观点:Linux 内核用 C 编写并利用 GCC 提供的扩展,2022 年从 GCC/Clang -std=gnu89 迁移到 -std=gnu11,文章探讨内核中这些 GNU 扩展的使用笔记。
关键信息和重要细节

  • Statement expressions:常用于宏中,如在 _wait_event 宏中用于循环控制等。
  • Local labels:某些宏利用此扩展在替换列表中重启 for 循环,如 _wait_event 宏中的 __label__ __out
  • Labels as values and computed goto statements:字节码解释器常用,BPF 等使用,在不同代码位置(如 drm_exec_retry_on_contention)有应用,在 PDC 和 PIC 中各有特点。
  • typeof__auto_typetypeof在众多代码中使用,__auto_type有少量出现,C23 标准化了它们。
  • Conditionals with omitted operands:“Elvis 算子”x?: y在众多代码中使用。
  • Empty structures:C 标准规定成员列表为空时行为未定义,空结构扩展可在配置选项禁用功能时使用,如 syscall_user_dispatch 结构的定义。
  • Case ranges:在内核中常用,可在 switch 语句中指定连续值范围的单个 case 标签。
  • Object size checking:glibc 2004 引入 _FORTIFY_SOURCE,Linux 内核 2017 - 07 引入 CONFIG_FORTIFY_SOURCE,两者利用内联函数和 __builtin_object_size 进行实现,Clang 也有相关实现。
  • Pragmas#pragma GCC diagnostic用于禁用本地诊断,#pragma GCC visibility("hidden")用于强制外部符号的直接访问,#pragma GCC poison用于禁止某些不期望的标识符,结构布局 pragmas 常用。
  • Inline assembly:用于硬件交互、性能优化、特殊设施实现等。
  • Built-in functions

    • 特殊机器码指令:GCC 提供内置函数生成特定任务的机器码指令。
    • __builtin_choose_expr:类似 ? :,条件为常量表达式,返回类型不受提升规则影响,在 GCC 中 C++不支持。
    • __builtin_constant_p:识别表达式是否可求值为常量,可用于条件静态断言、替代代码路径、常量折叠优化等,但常被滥用导致内核不能用 -O0 编译。
    • __builtin_expect:用于 likelyunlikely 宏给编译器优化提示。
    • __builtin_frame_address:用于栈跟踪实用程序。
    • __builtin_offsetof:用于实现 offsetof
    • __builtin_*_overflow:用于溢出检查。
    • __builtin_prefetch:作为 prefetchprefetchw 的默认实现。
    • __builtin_unreachable:用于告知不可达性以进行优化或抑制诊断。
    • __builtin_types_compatible_p:常用于模拟 C11 static_assert,或实现 C++函数重载等。
  • Function attributestools/include/linux/compiler.h定义许多常用属性的宏,tools/testing/selftests有一些 __attribute__((constructor)) 用于初始化,__attribute__((error(...)))用于静态断言等。
  • Variable attributes__attribute__((cleanup(...)))在变量超出范围时运行函数,include/linux/cleanup.h基于此定义 DEFINE_FREE__free
  • Type attributes__attribute__((aligned(...)))__attribute__((packed))常用于控制结构布局。
  • Language dialects

    • -fno-delete-null-pointer-checks:假设程序可安全地解引用空指针,代码或数据元素可位于地址零。
    • -fno-strict-aliasing:C11 标准定义的严格别名规则,编译器可利用其进行优化,可通过 -fno-strict-aliasing 禁用,Linus Torvalds 对其有保留意见。
    • -fno-strict-overflow:在 GCC 中等同于 -fwrapv -fwrapv-pointer,使有符号整数溢出使用环绕语义定义,虽避免未定义行为但可能隐藏意外算术溢出错误。
阅读 17
0 条评论