[Linux]学习笔记系列 -- compiler


title: compiler

categories:

  • linux
  • include
    tags:
  • linux
  • include
    abbrlink: aa62bd49
    date: 2025-10-03 09:01:49

https://github.com/wdfk-prog/linux-study

文章目录

  • include/linux/build_bug.h
    • [static_assert 静态编译警告](#static_assert 静态编译警告)
    • [BUILD_BUG_ON_MSG 中断编译提供BUG信息](#BUILD_BUG_ON_MSG 中断编译提供BUG信息)
    • [BUILD_BUG_ON_INVALID 不会生成编译时的警告](#BUILD_BUG_ON_INVALID 不会生成编译时的警告)
    • BUILD_BUG_ON
  • [include/linux/compiler.h 编译时完成](#include/linux/compiler.h 编译时完成)
    • [unreachable 不可达代码](#unreachable 不可达代码)
    • [likely && unlikely 优化分支预测](#likely && unlikely 优化分支预测)
      • [未启用CONFIG_TRACE_BRANCH_PROFILING 追踪分支分析](#未启用CONFIG_TRACE_BRANCH_PROFILING 追踪分支分析)
      • [启用CONFIG_TRACE_BRANCH_PROFILING 追踪分支分析](#启用CONFIG_TRACE_BRANCH_PROFILING 追踪分支分析)
    • [barrier 内存屏障](#barrier 内存屏障)
    • [is_signed_type is_unsigned_type 有符号类型 无符号类型](#is_signed_type is_unsigned_type 有符号类型 无符号类型)
    • [statically_true 编译时判断为常量](#statically_true 编译时判断为常量)
  • include/linux/compiler_types.h
    • [__cold 表示该函数很少被调用](#__cold 表示该函数很少被调用)
    • [__latent_entropy 随机性](#__latent_entropy 随机性)
    • [__always_inline 强制内联](#__always_inline 强制内联)
    • [__alloc_size __realloc_size 分配大小](#__alloc_size __realloc_size 分配大小)
    • [__force 强制转换](#__force 强制转换)
    • [compiletime_assert 中断编译提供BUG信息](#compiletime_assert 中断编译提供BUG信息)
    • BTF_TYPE_TAG
    • [__native_word 本机字节长度](#__native_word 本机字节长度)
    • [__unqual_scalar_typeof 用于获取变量的非限定标量类型](#__unqual_scalar_typeof 用于获取变量的非限定标量类型)
    • [noinstr 禁止内联插桩的段](#noinstr 禁止内联插桩的段)
    • [__same_type 类型是否相等](#__same_type 类型是否相等)
  • include/linux/kbuild.h
  • include/linux/kconfig.h

include/linux/build_bug.h

static_assert 静态编译警告

c 复制代码
/**
 * static_assert - 在构建时检查整数常量表达式
 *
 * static_assert() 是 C11 _Static_assert的包装器,具有
 * little 宏魔术使消息成为可选的(默认为
 * 测试表达式的字符串化)。
 *
 * 与 BUILD_BUG_ON() 相反,static_assert() 可以在 global
 * 范围,但要求表达式为整数常量
 * 表达式(即,__builtin_constant_p() 是不够的
 * true 表示 expr)。
 *
 * 另请注意BUILD_BUG_ON,如果条件为
 * true,而 static_assert() 如果表达式为
 *假。
 */
#define static_assert(expr, ...) __static_assert(expr, ##__VA_ARGS__, #expr)
#define __static_assert(expr, msg, ...) _Static_assert(expr, msg)

BUILD_BUG_ON_MSG 中断编译提供BUG信息

c 复制代码
/**
 * BUILD_BUG_ON_MSG - 如果条件为真,则中断编译并提供 emit
 *错误信息。
 * @condition:编译器应该知道的条件是 false。
 *
 * 有关说明,请参见 BUILD_BUG_ON。
 */
#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)

BUILD_BUG_ON_INVALID 不会生成编译时的警告

https://stackoverflow.com/questions/78432546/the-macro-build-bug-on-invalide-in-linux-kernel-seems-to-be-no-use

c 复制代码
/* BUILD_BUG_ON_INVALID() 允许编译器检查表达式的有效性,但避免生成任何代码,即使该表达式具有副作用。
 */
#define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e))))

BUILD_BUG_ON

c 复制代码
/**
 * BUILD_BUG_ON - 如果条件为 true,则中断编译。
 * @condition:编译器应该知道的条件是 false。
 *
 * 如果你有一些代码依赖于某些常量相等,或者
 * 其他一些编译时评估的条件,您应该使用 BUILD_BUG_ON 来
 * 检测是否有人更改它。
 */
#define BUILD_BUG_ON(condition) \
	BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)

include/linux/compiler.h 编译时完成

unreachable 不可达代码

  • unreachable 是一个宏,用于标记不可达的代码路径。它通常用于在编译器优化时提供提示,告诉编译器某些代码永远不会被执行。这可以帮助编译器进行更好的优化,并且在调试时可以帮助开发人员识别潜在的错误或不一致之处。
  • barrier_before_unreachable 是一个宏,用于在不可达代码之前插入一个屏障。这个屏障可以防止编译器对不可达代码进行优化,从而确保编译器不会删除或重排这些代码。这个宏通常用于调试和错误检查,以确保不可达代码在编译时不会被优化掉。
c 复制代码
#define unreachable() do {		\
	barrier_before_unreachable();	\
	__builtin_unreachable();	\
} while (0)

likely && unlikely 优化分支预测

  • unlikely(x) 的返回值与 x 的布尔值相同
  • likely(x) 的返回值与 x 的布尔值相同

未启用CONFIG_TRACE_BRANCH_PROFILING 追踪分支分析

  • __builtin_expect 是 GCC 提供的一个内建函数,用于向编译器提供分支预测信息。!!(x) 将 x 转换为布尔值,1 表示这个条件很可能为真。通过使用这个宏,开发者可以提示编译器优化代码路径,使得这个条件为真的情况执行得更快。
c 复制代码
#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)

启用CONFIG_TRACE_BRANCH_PROFILING 追踪分支分析

c 复制代码
#define __branch_check__(x, expect, is_constant) ({			\
			long ______r;					\
			static struct ftrace_likely_data		\
				__aligned(4)				\
				__section("_ftrace_annotated_branch")	\
				______f = {				\
				.data.func = __func__,			\
				.data.file = __FILE__,			\
				.data.line = __LINE__,			\
			};						\
			______r = __builtin_expect(!!(x), expect);	\
			ftrace_likely_update(&______f, ______r,		\
					     expect, is_constant);	\
			______r;					\
		})

/*
 * Using __builtin_constant_p(x) to ignore cases where the return
 * value is always the same.  This idea is taken from a similar patch
 * written by Daniel Walker.
 */
# ifndef likely
#  define likely(x)	(__branch_check__(x, 1, __builtin_constant_p(x)))
# endif
# ifndef unlikely
#  define unlikely(x)	(__branch_check__(x, 0, __builtin_constant_p(x)))
# endif

barrier 内存屏障

  • barrier 是一个宏,用于在编译器优化时插入一个内存屏障。内存屏障是一种指令,用于防止编译器和处理器对内存操作进行重排序,从而确保内存操作的顺序性。这在多线程和并发编程中非常重要,因为它可以确保不同线程之间的内存访问是可预测的。
c 复制代码
# define barrier() __asm__ __volatile__("": : :"memory")
  • : : : "memory" 是汇编指令的操作数部分。"memory" 告诉编译器,这段汇编代码会影响内存的状态,因此编译器在这段代码之前和之后不能对内存访问进行重新排序。

is_signed_type is_unsigned_type 有符号类型 无符号类型

c 复制代码
/*
 * 'type' 是有符号类型还是无符号类型。支持标量类型,
 * bool 以及指针类型。
 */
#define is_signed_type(type) (((type)(-1)) < (__force type)1)
#define is_unsigned_type(type) (!is_signed_type(type))

statically_true 编译时判断为常量

c 复制代码
/*
 * "Is this condition know at compile-work?" 的有用简写
 *
 * 请注意,该条件可能涉及非常量值,但编译器可能对这些值的详细信息有足够的了解,从而确定该条件是否为静态 true。
 */
#define statically_true(x) (__builtin_constant_p(x) && (x))

include/linux/compiler_types.h

__cold 表示该函数很少被调用

  • 这是 GCC 编译器的一个属性,表示该函数很少被调用。编译器可以利用这个信息进行优化,例如将这些函数放置在不常用的代码段中,减少对常用代码段的干扰,从而提高缓存命中率和整体性能。
  • CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT:
    • 这个宏用于检查编译器是否支持合理的函数对齐。函数对齐是指将函数的起始地址对齐到特定的字节边界,以提高访问效率和性能。
  • CONFIG_FUNCTION_ALIGNMENT:
    • 这个宏用于设置函数的对齐方式。函数对齐可以提高函数调用的效率,尤其是在某些架构上,函数调用需要特定的对齐方式才能正常工作。
c 复制代码
#if defined(CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT) || (CONFIG_FUNCTION_ALIGNMENT == 0)
#define __cold				__attribute__((__cold__))
#else
#define __cold
#endif

__latent_entropy 随机性

  • 这个属性通常用于内核开发中,特别是在 Linux 内核中。它用于标记那些在系统启动时需要一些随机性(entropy)的函数或变量。通过使用这个属性,编译器会确保在系统启动时,这些函数或变量能够获得一些随机数据,从而增强系统的安全性和不可预测性
c 复制代码
#if defined(LATENT_ENTROPY_PLUGIN) && !defined(__CHECKER__)
#define __latent_entropy __attribute__((latent_entropy))
#endif

__always_inline 强制内联

  • __attribute__((__always_inline__)) 是 GCC 编译器特定的扩展属性,强制编译器始终内联标记的函数,即使在优化级别较低的情况下也会内联。这对于性能关键的代码段非常有用,因为它确保了函数调用的开销被最小化。
c 复制代码
#define __always_inline                 inline __attribute__((__always_inline__))

__alloc_size __realloc_size 分配大小

  • __alloc_size__realloc_size 是 GCC 编译器的属性,用于标记函数的参数,以指示这些参数表示分配的内存大小。这些属性可以帮助编译器进行更好的优化和静态分析,确保在内存分配时使用正确的大小。

__force 强制转换

  • __force 是 GCC 编译器的一个属性,用于强制类型转换。它通常用于指示编译器在进行类型转换时要强制执行,而不考虑潜在的类型不匹配或警告。这在某些情况下是有用的,例如在处理低级别的硬件编程或内核开发时。
c 复制代码
#define __force	__attribute__((force))

compiletime_assert 中断编译提供BUG信息

  1. 启用__OPTIMIZE__时,将prefix与suffix连接成一个函数,并且这个函数是__compiletime_error类型的,这个函数会在编译时检查条件是否成立。

  2. 如果条件不成立,则调用这个函数,从而中断编译并提供错误信息。

  3. __COUNTER__是一个预定义宏,它在每次使用时都会递增,用于生成唯一的后缀,确保每次调用compiletime_assert时都生成不同的函数名。所以prefix##suffix将会生成一个唯一的函数名。

    • 例如
    c 复制代码
    	__noreturn extern void prefix ## suffix(void)		\
    		__compiletime_error(msg);			\
        __noreturn extern void __compiletime_assert_1(void) __compiletime_error("int size is not 4 bytes");
c 复制代码
#ifdef __OPTIMIZE__
# define __compiletime_assert(condition, msg, prefix, suffix)		\
	do {								\
		/*							\
		 * 需要__noreturn来为编译器提供足够的 \
		 * 避免某些可能未初始化的信息 \
		 * 警告(无论构建是否失败)。		\
		 */							\
		__noreturn extern void prefix ## suffix(void)		\
			__compiletime_error(msg);			\
		if (!(condition))					\
			prefix ## suffix();				\
	} while (0)
#else
# define __compiletime_assert(condition, msg, prefix, suffix) do { } while (0)
#endif

#define _compiletime_assert(condition, msg, prefix, suffix) \
	__compiletime_assert(condition, msg, prefix, suffix)

/**
 * compiletime_assert - 如果 Condition 为 false,则中断构建并发出 msg
 * @condition:要检查的编译时常量条件
 * @msg:如果 condition 为 false,则发出一条消息
 *
 * 按照 POSIX 断言的传统,如果
 * 提供的条件为 *false*,如果
 * 编译器支持这样做。
 */
#define compiletime_assert(condition, msg) \
	_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)

BTF_TYPE_TAG

  • BTF_TYPE_TAG 是一个宏,用于在编译时为类型添加 BTF(BPF Type Format)标签。BTF 是一种用于描述内核数据结构的格式,主要用于 BPF(Berkeley Packet Filter)程序的类型信息。
  • 通过添加 btf_type_tag 属性,可以为类型提供额外的元数据,帮助调试和分析工具更好地理解和处理这些类型。
c 复制代码
#if defined(CONFIG_DEBUG_INFO_BTF) && defined(CONFIG_PAHOLE_HAS_BTF_TAG) && \
	__has_attribute(btf_type_tag) && !defined(__BINDGEN__)
# define BTF_TYPE_TAG(value) __attribute__((btf_type_tag(#value)))
#else
# define BTF_TYPE_TAG(value) /* nothing */
#endif

__native_word 本机字节长度

c 复制代码
/* 此类型是本机字大小吗 -- 对原子作有用 */
#define __native_word(t) \
	(sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || \
	 sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))

__unqual_scalar_typeof 用于获取变量的非限定标量类型

  • _Generic: _Generic 是 C11 标准中的一种泛型选择机制,它根据表达式的类型选择一个对应的表达式。在这里,它用于选择适当的类型转换表达式
c 复制代码
/*
 * __unqual_scalar_typeof(x) - 声明一个非限定标量类型,留下
 * 非标量类型保持不变。
 */
/*
 * 首选 C11 _Generic以获得更好的编译时间和更简单的代码。注意: 'char'
 * 与 'signed char' 类型不兼容,我们定义一个单独的 case。
 */
#define __scalar_type_to_expr_cases(type)				\
		unsigned type:	(unsigned type)0,			\
		signed type:	(signed type)0

#define __unqual_scalar_typeof(x) typeof(				\
		_Generic((x),						\
			 char:	(char)0,				\
			 __scalar_type_to_expr_cases(char),		\
			 __scalar_type_to_expr_cases(short),		\
			 __scalar_type_to_expr_cases(int),		\
			 __scalar_type_to_expr_cases(long),		\
			 __scalar_type_to_expr_cases(long long),	\
			 default: (x)))

noinstr 禁止内联插桩的段

  1. noinstr 是一个内核特定的函数属性,用于标记那些不允许插入任何额外代码(如调试、性能分析或跟踪代码)的函数。这些函数通常是与硬件或中断处理密切相关的关键代码,任何额外的插桩代码都可能导致不可预测的行为或性能问题。
c 复制代码
/* Section for code which can't be instrumented at all */
#define __noinstr_section(section)					\
	noinline notrace __attribute((__section__(section)))		\
	__no_kcsan __no_sanitize_address __no_profile __no_sanitize_coverage \
	__no_sanitize_memory __signed_wrap

#define noinstr __noinstr_section(".noinstr.text")

__same_type 类型是否相等

c 复制代码
/* Are two types/vars the same type (ignoring qualifiers)? */
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))

include/linux/kbuild.h

  • 定义了.c生成.s的相关宏
c 复制代码
#define DEFINE(sym, val) \
	asm volatile("\n.ascii \"->" #sym " %0 " #val "\"" : : "i" (val))

#define BLANK() asm volatile("\n.ascii \"->\"" : : )

#define OFFSET(sym, str, mem) \
	DEFINE(sym, offsetof(struct str, mem))

#define COMMENT(x) \
	asm volatile("\n.ascii \"->#" x "\"")

include/linux/kconfig.h

  1. #define __ARG_PLACEHOLDER_1 0,定义了一个宏__ARG_PLACEHOLDER_1,它的值是0,。这个宏用于在后续的宏中作为占位符。
  2. 如果宏没有定义,则这里的__ARG_PLACEHOLDER_1将不会被替换,而是直接使用0,作为参数。
  3. #define __take_second_arg(__ignored, val, ...) val定义了一个宏__take_second_arg,它接受多个参数,但只返回第二个参数val。这个宏用于在后续的宏中提取第二个参数。
  4. 所以宏有定义,则返回第二个参数1,没有定义,则返回第3个参数0
c 复制代码
#define __ARG_PLACEHOLDER_1 0,
#define __take_second_arg(__ignored, val, ...) val

/*
 * The use of "&&" / "||" is limited in certain expressions.
 * The following enable to calculate "and" / "or" with macro expansion only.
 */
#define __and(x, y)			___and(x, y)
#define ___and(x, y)			____and(__ARG_PLACEHOLDER_##x, y)
#define ____and(arg1_or_junk, y)	__take_second_arg(arg1_or_junk y, 0)

#define __or(x, y)			___or(x, y)
#define ___or(x, y)			____or(__ARG_PLACEHOLDER_##x, y)
#define ____or(arg1_or_junk, y)		__take_second_arg(arg1_or_junk 1, y)

/*
 * Helper macros to use CONFIG_ options in C/CPP expressions. Note that
 * these only work with boolean and tristate options.
 */

/*
 * Getting something that works in C and CPP for an arg that may or may
 * not be defined is tricky.  Here, if we have "#define CONFIG_BOOGER 1"
 * we match on the placeholder define, insert the "0," for arg1 and generate
 * the triplet (0, 1, 0).  Then the last step cherry picks the 2nd arg (a one).
 * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
 * the last step cherry picks the 2nd arg, we get a zero.
 */
#define __is_defined(x)			___is_defined(x)
#define ___is_defined(val)		____is_defined(__ARG_PLACEHOLDER_##val)
#define ____is_defined(arg1_or_junk)	__take_second_arg(arg1_or_junk 1, 0)

/*
 * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
 * otherwise. For boolean options, this is equivalent to
 * IS_ENABLED(CONFIG_FOO).
 */
#define IS_BUILTIN(option) __is_defined(option)

/*
 * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0
 * otherwise.  CONFIG_FOO=m results in "#define CONFIG_FOO_MODULE 1" in
 * autoconf.h.
 */
#define IS_MODULE(option) __is_defined(option##_MODULE)

/*
 * IS_REACHABLE(CONFIG_FOO) evaluates to 1 if the currently compiled
 * code can call a function defined in code compiled based on CONFIG_FOO.
 * This is similar to IS_ENABLED(), but returns false when invoked from
 * built-in code when CONFIG_FOO is set to 'm'.
 */
#define IS_REACHABLE(option) __or(IS_BUILTIN(option), \
				__and(IS_MODULE(option), __is_defined(MODULE)))

/*
 * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
 * 0 otherwise.  Note that CONFIG_FOO=y results in "#define CONFIG_FOO 1" in
 * autoconf.h, while CONFIG_FOO=m results in "#define CONFIG_FOO_MODULE 1".
 */
#define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option))
相关推荐
heda32 小时前
zip在linux上解压出错Unicode编码-解决
linux·运维·python
济6172 小时前
linux 系统移植(第四期)--Uboot移植(4)--在U-Boot 中添加自己的开发板(3) -网络驱动修改-- Ubuntu20.04
linux·运维·服务器
2301_765715142 小时前
Linux虚拟机NAT模式网络故障解析与修复指南
linux·运维·服务器
星火开发设计2 小时前
从公式到应用:卷积公式全面解析与实战指南
学习·算法·机器学习·概率论·知识·期末考试·卷积公式
焦糖布丁的午夜2 小时前
数据库大王mysql---linux
linux·数据库·mysql
九成宫2 小时前
计算机网络期末复习——第4章:网络层 Part Two
网络·笔记·计算机网络·软件工程
实战项目2 小时前
云原生中间件的消息队列性能优化
学习
玄〤2 小时前
黑马点评中的分布式锁设计与实现(Redis + Redisson)
java·数据库·redis·笔记·分布式·后端
Yu_Lijing2 小时前
基于C++的《Head First设计模式》笔记——适配器模式
c++·笔记·设计模式