【Linux驱动基础详解】| Linux模块声明与描述

img
个人主页:董哥聊技术
我是董哥,嵌入式领域新星创作者
创作理念:专注分享高质量嵌入式文章,让大家读有所得!
img

文章目录

    • 1、前言
    • 2、MODULE_XXX分析
    • 3、MODULE_INFO
    • 4、查看模块信息

【Linux驱动基础详解】| Linux模块声明与描述_第1张图片

1、前言

我们在编写一个模块的时候,常常使用一些宏定义来标识模块的作者,版本,以及相关信息的描述,如:MODULE_AUTHORMODULE_DESCRIPTIONMODULE_LICENSEMODULE_ALIAS等,那么这些宏是如何进行管理的呢?

小处诚实非小事!

今天带着大家,我们来深入分析一下这些宏定义,其内部的奥秘!

 

2、MODULE_XXX分析

在上面提到的MODULE_AUTHORMODULE_DESCRIPTIONMODULE_LICENSEMODULE_ALIAS,这些宏定义,查看其声明,我们发现:

/* For userspace: you can also call me... */
#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)

/* Soft module dependencies. See man modprobe.d for details.
 * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz")
 
 /*
 * The following license idents are currently accepted as indicating free
 * software modules
 *
 *	"GPL"				[GNU Public License v2 or later]
 *	"GPL v2"			[GNU Public License v2]
 *	"GPL and additional rights"	[GNU Public License v2 rights and more]
 *	"Dual BSD/GPL"			[GNU Public License v2
 *					 or BSD license choice]
 *	"Dual MIT/GPL"			[GNU Public License v2
 *					 or MIT license choice]
 *	"Dual MPL/GPL"			[GNU Public License v2
 *					 or Mozilla license choice]
 *
 * The following other idents are available
 *
 *	"Proprietary"			[Non free products]
 *
 * There are dual licensed components, but when running with Linux it is the
 * GPL that is relevant so this is a non issue. Similarly LGPL linked with GPL
 * is a GPL combined work.
 *
 * This exists for several reasons
 * 1.	So modinfo can show license info for users wanting to vet their setup
 *	is free
 * 2.	So the community can ignore bug reports including proprietary modules
 * 3.	So vendors can do likewise based on their own policies
 */
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)

/*
 * Author(s), use "Name " or just "Name", for multiple
 * authors use multiple MODULE_AUTHOR() statements/lines.
 */
#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)

/* What your module does. */
#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)

无论是MODULE_LICENSEMODULE_AUTHOR、还是MODULE_DESCRIPTION,其最终都调用了MODULE_INFO的宏定义,并将对应的字符串参数传入进去。

那么关键就在于MODULE_INFO这个宏定义了!

 

3、MODULE_INFO

查看MODULE_INFO的定义,写成了我们看不懂的形式,下面我们来逐步分析

// include/linux/module.h

/* Generic info of form tag = "info" */
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)

// include/linux/moduleparam.h
#define __MODULE_INFO(tag, name, info)					  \
static const char __UNIQUE_ID(name)[]					  \
  __used __attribute__((section(".modinfo"), unused, aligned(1)))	  \
  = __stringify(tag) "=" info

// include/linux/compiler-gcc.h
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)

// include/linux/compiler_types.h
#define ___PASTE(a,b) a##b
#define __PASTE(a,b) ___PASTE(a,b)

上面是MODULE_INFO的完整定义,其目的是为了生成唯一的字符串

下面我们举个例子:

MODULE_AUTHOR(donge)

//	#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
MODULE_INFO(author, donge)
    
//	#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
__MODULE_INFO(author, author, donge)
    
//#define __MODULE_INFO(tag, name, info)					  \
//static const char __UNIQUE_ID(name)[]					  \
//  __used __attribute__((section(".modinfo"), unused, aligned(1)))	  \
//  = __stringify(tag) "=" info
static const char __UNIQUE_ID(author)[]		\
    __used __attribute__((section(".modinfo"), unused, aligned(1)))	\
    = __stringify(author) "=" donge

// #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
static const char __PASTE(__PASTE(__UNIQUE_ID_, author), __COUNTER__)[]		\
    __used __attribute__((section(".modinfo"), unused, aligned(1)))	\
    = __stringify(author) "=" donge
    
// #define ___PASTE(a,b) a##b
// #define __PASTE(a,b) ___PASTE(a,b)

static const char __UNIQUE_ID_author__COUNTER__[]		\
    __used __attribute__((section(".modinfo"), unused, aligned(1)))	\
    = __stringify(author) "=" donge

//	__COUNTER__会被展开为一个从0开始的整数,每次调用都会加一
static const char __UNIQUE_ID_author0[]			\
    __used __attribute__((section(".modinfo"), unused, aligned(1)))	\
    = __stringify(author) "=" donge
    
//	#define __stringify_1(x...) #x
//	#define __stringify(x...)   __stringify_1(x)
static const char __UNIQUE_ID_author0[]			\
    __used __attribute__((section(".modinfo"), unused, aligned(1)))	\
    = "author=donge"

现在我们对这些宏定义了如指掌了吧,下面来分析一下部分属性的含义

  • aligned:指定变量或结构域的起始地址对齐(以字节为单位)

  • used:通知编译器在目标文件中保留一个静态函数,即使它没有被引用。

  • attribute__((used)):被标记在目标文件中,以避免链接器删除未使用的节。

  • __attribute__((section(".modinfo"))):将被修饰的变量或函数编译到特定的一块内存空间的位置

  • __attribute__((used)):描述静态变量

  • unused:表明该函数或者变量可能不使用,避免编译器产生警告信息。

  • #和##:我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.

 

4、查看模块信息

我们通过MODULE_XXXX设置的信息,怎么去查看呢?通过lsmod xxx.ko命令

[r8-common-vrf dong@ubuntu ~/WorkSpace/arobot_buildroot/output/r8-common-vrf/build/linux-refs_remotes_origin_r8_develop/drivers/char]$ modinfo arobot-rp-r8.ko
filename:       /home/dong/WorkSpace/arobot_buildroot/output/r8-common-vrf/build/linux-refs_remotes_origin_r8_develop/drivers/char/arobot-rp-r8.ko
description:    Arobot processor B driver
author:         Amicro
license:        GPL
alias:          of:N*T*Carobot,r8-rpC*
alias:          of:N*T*Carobot,r8-rp
depends:        
intree:         Y
name:           arobot_rp_r8
vermagic:       4.19.123 SMP preempt mod_unload ARMv7 p2v8 

 

OK,上文较为详细介绍了Kernel内部MODULE_INFO的详细实现,还有一些重要的知识点没有展开介绍,例如:__attribute__((section(".xxx")))的作用,后续再起一篇文章介绍。

 

img

点赞+关注,永远不迷路

img

你可能感兴趣的:(Linux,API接口详解,linux,嵌入式硬件,Linux驱动开发,Linux,API,Linux源码详解)