Kernel之vermagic

内核的vermagic

内核的vermagic类似于:5.4.96-xx SMP preempt mod_unload aarch64

内核的vermagic即为VERMAGIC_STRING``(include/linux/vermagic.h)

static const char vermagic[] = VERMAGIC_STRING;

/* Simply sanity version stamp for modules. */
#ifdef CONFIG_SMP
#define MODULE_VERMAGIC_SMP "SMP "
#else
#define MODULE_VERMAGIC_SMP ""
#endif
#ifdef CONFIG_PREEMPT
#define MODULE_VERMAGIC_PREEMPT "preempt "
#elif defined(CONFIG_PREEMPT_RT)
#define MODULE_VERMAGIC_PREEMPT "preempt_rt "
#else
#define MODULE_VERMAGIC_PREEMPT ""
#endif
#ifdef CONFIG_MODULE_UNLOAD
#define MODULE_VERMAGIC_MODULE_UNLOAD "mod_unload "
#else
#define MODULE_VERMAGIC_MODULE_UNLOAD ""
#endif
#ifdef CONFIG_MODVERSIONS
#define MODULE_VERMAGIC_MODVERSIONS "modversions "
#else
#define MODULE_VERMAGIC_MODVERSIONS ""
#endif
#ifndef MODULE_ARCH_VERMAGIC
#define MODULE_ARCH_VERMAGIC ""
#endif
#ifdef RANDSTRUCT_PLUGIN
#include <generated/randomize_layout_hash.h>
#define MODULE_RANDSTRUCT_PLUGIN "RANDSTRUCT_PLUGIN_" RANDSTRUCT_HASHED_SEED
#else
#define MODULE_RANDSTRUCT_PLUGIN
#endif

#define VERMAGIC_STRING 						\
	UTS_RELEASE " "							\
	MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT 			\
	MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS	\
	MODULE_ARCH_VERMAGIC						\
	MODULE_RANDSTRUCT_PLUGIN

其中UTS_RELEASE是在最顶层的Makefile中定义的,即为KERNELRELEASE

uts_len := 64
define filechk_utsrelease.h
	if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \
	  echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2;    \
	  exit 1;                                                         \
	fi;                                                               \
	(echo \#define UTS_RELEASE \"$(KERNELRELEASE)\";		\
	echo \#define SOURCE_VERSION \"$(SOURCEVERSION)\";)
endef

所以从上面代码可以看出:
vermagic= VERMAGIC_STRING= UTS_RELEASE+ 其他 = KERNELRELEASE+ 其他
注:其他基本上都是由配置所决定,所以这里不做过多讨论,下面来看看KERNELRELEASE

KERNELRELEASE

KERNELRELEASE是在编译过程中生成的,保存在include/config/kernel.release,主要过程是在最顶层的Makefile:
include/config/kernel.release中读取:

# Read KERNELRELEASE from include/config/kernel.release (if it exists)
KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
SOURCEVERSION = $(shell git rev-parse HEAD 2> /dev/null)
ifeq ($(SOURCEVERSION),)
SOURCEVERSION = $(shell cat .sourceversion | head -n 1 2>/dev/null)
endif

export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION

保存新的KERNELRELEASEinclude/config/kernel.release:

filechk_kernel.release = \
	echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))"

# Store (new) KERNELRELEASE string in include/config/kernel.release
include/config/kernel.release: FORCE
	$(call filechk,kernel.release)

这里可以看到KERNELRELEASE主要由2部分组成:

  1. KERNELVERSION: 从上面的代码可以看出,其主要是由Makefile最前面的那几个版本变量决定的(VERSION、PATCHLEVEL、SUBLEVEL、EXTRAVERSION)
  2. scripts/setlocalversion脚本生成的内容

setlocalversion脚本

setlocalversion脚本部分主要代码:

# localversion* files in the build and source directory
res="$(collect_files localversion*)"
if test ! "$srctree" -ef .; then
        res="$res$(collect_files "$srctree"/localversion*)"
fi

# CONFIG_LOCALVERSION and LOCALVERSION (if set)
res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"

# scm version string if not at a tagged commit
if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then
        # full scm version string
        res="$res$(scm_version)"
else
        # append a plus sign if the repository is not in a clean
        # annotated or signed tagged state (as git describe only
        # looks at signed or annotated tags - git tag -a/-s) and
        # LOCALVERSION= is not specified
        if test "${LOCALVERSION+set}" != "set"; then
                scm=$(scm_version --short)
                res="$res${scm:++}"
        fi
fi

echo "$res"

setlocalversion输出结果:

  1. 如果源代码或编译目录存在localversion*文件,添加进去
  2. 如果定义了CONFIG_LOCALVERSION 或者 LOCALVERSION变量,依次添加进去
  3. 如果CONFIG_LOCALVERSION_AUTO配置为y,会追加版本控制工具(git、svn、mercurial)生成的版本信息
  4. 如果CONFIG_LOCALVERSION_AUTO未配置,且LOCALVERSION变量为空,追加+,如”5.4.96+”

最终localversion信息为:
[localversion*] [CONFIG_LOCALVERSION] [LOCALVERSION] [版本控制工具版本信息]

[localversion*] [CONFIG_LOCALVERSION] [LOCALVERSION][+]
注:CONFIG_LOCALVERSION为config配置里面的配置选项

参考

  • 内核源码及文档