MODULE_LICENCE 机制

本文深入探讨了MODULE_LICENSE宏的展开过程,并通过实例展示了如何将DualBSD/GPL许可应用于Linux内核模块。同时,文章解释了相关预处理过程、行号变量__LINE__的用途,以及模块结构中modinfo段的作用。

源代码解析:宏MODULE_LICENSE("Dual BSD/GPL")的展开

MODULE_LICENSE()在module.h定义为
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)

MODULE_INFO定义为
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)

在moduleparam.h中__MODULE_INFO定义为
#define ___module_cat(a,b) __mod_ ## a ## b
#define __module_cat(a,b) ___module_cat(a,b)
#define __MODULE_INFO(tag, name, info)                    \
static const char __module_cat(name,__LINE__)[]                \
__attribute_used__                            \
__attribute__((section(".modinfo"),unused)) = __stringify(tag) "=" info

__stringify(tag)在stringify.h中
#define __stringify_1(x)    #x
#define __stringify(x)        __stringify_1(x)
这个宏够复杂的,我就想看看预处理后这个宏变成了什么。
和前篇一样
[root@localhost helloworld]# gcc -I /lib/modules/2.6.23.1-4/build/include -E -P -< hello.c > hhhhh.c
In file included from /lib/modules/2.6.23.1-4/build/include/linux/module.h:9,
                 from <stdin>:5:
/lib/modules/2.6.23.1-4/build/include/linux/list.h:970:2: warning: #warning "don't include kernel headers in userspace"
In file included from /lib/modules/2.6.23.1-4/build/include/linux/module.h:20,
                 from <stdin>:5:
/lib/modules/2.6.23.1-4/build/include/asm/module.h:64:2: error: #error unknown processor family
这个报错把我搞傻了,"don't include kernel headers in userspace"这句话让我挠头,在makefile中改也没搞定,有知道的告诉我一声。
没办法,就用蠢办法,修改hello.c
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)

#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)


#define ___module_cat(a,b) __mod_ ## a ## b
#define __module_cat(a,b) ___module_cat(a,b)
#define __MODULE_INFO(tag, name, info)                    \
static const char __module_cat(name,__LINE__)[]                \
__attribute_used__                            \
__attribute__((section(".modinfo"),unused)) = __stringify(tag) "=" info

#define __stringify_1(x)    #x
#define __stringify(x)        __stringify_1(x)

MODULE_LICENSE("Dual BSD/GPL");
int main()
{
    return 1;

是的,我就是只想看看
MODULE_LICENSE("Dual BSD/GPL");变成什么
特别要提的是__LINE__是当前的行号,对于调用是调用时的行号,
接着来吧
gcc -E -P -< hello.c > hh.c

结果hh.c是
static const char __mod_license16[] __attribute_used__ __attribute__((section(".modinfo"),unused)) = "license" "=" "Dual BSD/GPL";
int main()
{
return 1;
}
至于__attribute_used__这些修饰符,我暂时也不确定是什么用的,虽然看了gcc的手册,__attribute_unused__好像是表示在修饰的函数未使用的情况下不出现警告。
有两点还要说的,一个是那个section(".modinfo"),我只知道这是模块结构中的一个段,对于我们原先的hello模块(不是这个,是以前那个),段信息如下
[guobamantou@localhost helloworld]$ objdump -t hello.o

hello.o:     file format elf32-i386

SYMBOL TABLE:
00000000 l    df *ABS* 00000000 hello.c
00000000 l    d .text 00000000 .text
00000000 l    d .data 00000000 .data
00000000 l    d .bss   00000000 .bss
00000000 l    d .rodata.str1.1 00000000 .rodata.str1.1
00000000 l     F .text 00000011 hello_exit
00000011 l     F .text 00000013 hello_init
00000000 l    d .modinfo       00000000 .modinfo
00000000 l     O .modinfo       00000015 __mod_license6
00000000 l    d .note.GNU-stack        00000000 .note.GNU-stack
00000000 l    d .comment       00000000 .comment
00000000         *UND* 00000000 printk
00000011 g     F .text 00000013 init_module
00000000 g     F .text 00000011 cleanup_module
使用modinfo命令
[root@localhost helloworld]# /sbin/modinfo hello.ko
filename:       hello.ko
license:        Dual BSD/GPL
srcversion:     ABC142F4744F0BE5A5047D1
depends:
vermagic:       2.6.23.1-4 SMP mod_unload 686

可见modinfo这个段的信息(modinfo命令学自http://linux.chinaunix.net/bbs/archiver/?tid-963292.html)

第二。就是那个字符串的初始化,static const char __mod_license16[]="license" "=" "Dual BSD/GPL";这显然是我们不习惯了,试过了,的确是可以的。看过《C++编程思想》的读者也许记得书中讲过类似 char str[]="xxxx"
                                                                                "11111";
这样换行的赋值都是正确的。
<think>我们正在解决内核模块编译错误,具体包括三个问题:1.在void函数中使用了带返回值的return语句2.MODULE_LICENSE拼写错误(写成了MODULE_LICENCE)3.MODULE_VERSION缺少分号同时,我们是在arm64架构下为RK3588平台编译。解决方案:第一步:修复源代码中的错误第二步:确保Makefile正确配置(针对arm64交叉编译)第三步:重新编译详细步骤:</think>### 解决内核模块编译错误指南(ARM64架构) #### 错误1:void函数中使用带返回值的`return`语句 **问题分析**: 在void函数中使用`return value;`会导致类型不匹配错误。void函数只能使用`return;`或不使用return语句[^1]。 **修复示例**: ```c // 错误写法 void cleanup_module(void) { printk("Cleaning up\n"); return 0; // 在void函数中返回值 } // 正确写法 void cleanup_module(void) { printk("Cleaning up\n"); return; // 仅返回不携带值 } ``` #### 错误2:`MODULE_LICENSE`拼写错误 **问题分析**: `MODULE_LICENCE`是错误拼写,正确应为`MODULE_LICENSE`。拼写错误会导致模块加载失败[^2]。 **修复示例**: ```c // 错误写法 MODULE_LICENCE("GPL"); // 拼写错误 // 正确写法 MODULE_LICENSE("GPL"); // 正确拼写 ``` #### 错误3:`MODULE_VERSION`缺少分号 **问题分析**: 宏定义后缺少分号是常见语法错误,会导致编译中断。 **修复示例**: ```c // 错误写法 MODULE_VERSION("1.0") // 缺少分号 // 正确写法 MODULE_VERSION("1.0"); // 添加分号 ``` #### 完整修复后的模块示例 ```c #include <linux/init.h> #include <linux/module.h> static int __init hello_init(void) { printk(KERN_INFO "Hello module loaded\n"); return 0; } static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye\n"); // 正确使用void返回 } // 修复所有错误 MODULE_LICENSE("GPL"); // 正确拼写 MODULE_AUTHOR("Your Name"); MODULE_VERSION("1.0"); // 添加分号 module_init(hello_init); module_exit(hello_exit); ``` #### ARM64架构编译要点 1. **确保Makefile配置正确**: ```makefile obj-m := hello.o ARCH := arm64 CROSS_COMPILE := aarch64-linux-gnu- KDIR := /path/to/rk3588/kernel all: $(MAKE) -C $(KDIR) M=$(PWD) modules ``` 2. **验证编译环境**: ```bash # 检查工具链 aarch64-linux-gnu-gcc --version # 清理后重新编译 make clean && make -j$(nproc) ``` 3. **加载模块测试**: ```bash # ARM64设备上执行 sudo insmod hello.ko dmesg | tail -n 2 # 应显示加载/卸载信息 ``` > **调试提示**:使用`gcc -Wall -Werror`编译选项可捕获更多语法错误[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值