owned this note
owned this note
Published
Linked with GitHub
# 2024q1 Homework6 (integration)
contributed by < ChengChaoChun >
## Linux 核心模組掛載機制
ksort 使用的授權條款:
`MODULE_LICENSE("Dual MIT/GPL");`
目前自由軟體模組被接受的授權條款:
```
* The following license idents are currently accepted as indicating free
* software modules
*
* "GPL" [GNU Public License v2]
* "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]
```
在 `include/linux/module.h` 中 `MODULE_LICENSE` 的定義
```
#define MODULE_LICENSE(_license) MODULE_FILE MODULE_INFO(license, _license)
```
根據註解可以知道 `MODULE_FILE` 在建構模組時不會有作用
```
/*
* MODULE_FILE is used for generating modules.builtin
* So, make it no-op when this is being built as a module
*/
#ifdef MODULE
#define MODULE_FILE
#else
#define MODULE_FILE MODULE_INFO(file, KBUILD_MODFILE);
#endif
```
因此將 `MODULE_LICENSE("Dual MIT/GPL");` 展開後就是 `MODULE_INFO(license, "Dual MIT/GPL")` 。
`MODULE_INFO` 是這樣定義的
```
/* Generic info of form tag = "info" */
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
```
接著再展開,`__MODULE_INFO(license, license, "Dual MIT/GPL")`。
`__MODULE_INFO` 的定義在 `/include/linux/moduleparam.h`
```
#define __MODULE_INFO(tag, name, info) \
static const char __UNIQUE_ID(name)[] \
__used __section(".modinfo") __aligned(1) \
= __MODULE_INFO_PREFIX __stringify(tag) "=" info
```
展開:
```
static const char __UNIQUE_ID(license)[] \
__used __section(".modinfo") __aligned(1) \
= __MODULE_INFO_PREFIX __stringify(license) "=" "Dual MIT/GPL"
```
`__UNIQUE_ID` 的定義在 `include/linux/compiler.h`
`#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)`
展開:
```
static const char __PASTE(__PASTE(__UNIQUE_ID_, license), __COUNTER__)[] \
__used __section(".modinfo") __aligned(1) \
= __MODULE_INFO_PREFIX __stringify(license) "=" "Dual MIT/GPL"
```
`__PASTE` 的定義在 `include/linux/compiler_types.h`
```
/* Indirect macros required for expanded argument pasting, eg. __LINE__. */
#define ___PASTE(a,b) a##b
#define __PASTE(a,b) ___PASTE(a,b)
```
先將內層`__PASTE`展開:
```
static const char __PASTE(__UNIQUE_ID_license), __COUNTER__)[] \
__used __section(".modinfo") __aligned(1) \
= __MODULE_INFO_PREFIX __stringify(license) "=" "Dual MIT/GPL"
```
再展開外層`__PASTE`:
```
static const char __UNIQUE_ID_license__COUNTER__[] \
__used __section(".modinfo") __aligned(1) \
= __MODULE_INFO_PREFIX __stringify(license) "=" "Dual MIT/GPL"
```
`__MODULE_INFO_PREFIX` 定義在 `include/linux/moduleparam.h`,在這裡 `__MODULE_INFO_PREFIX` 的定義為空。
```
/* You can override this manually, but generally this should match the
module name. */
#ifdef MODULE
#define MODULE_PARAM_PREFIX /* empty */
#define __MODULE_INFO_PREFIX /* empty */
#else
#define MODULE_PARAM_PREFIX KBUILD_MODNAME "."
/* We cannot use MODULE_PARAM_PREFIX because some modules override it. */
#define __MODULE_INFO_PREFIX KBUILD_MODNAME "."
#endif
```
`__stringify` 的定義在 `include/linux/stringify.h`
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x
展開:
```
static const char __UNIQUE_ID_license__COUNTER__[] \
__used __section(".modinfo") __aligned(1) \
= "license = Dual MIT/GPL"
```
藉由 strace 追蹤 Linux 核心的掛載
```
$ sudo strace insmod sort.ko
execve("/usr/sbin/insmod", ["insmod", "sort.ko"], 0x7fffe5fd7228 /* 27 vars */) = 0
brk(NULL) = 0x5ee115bcd000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffef17b6760) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7bfb20698000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
...
finit_module(3, "", 0) = 0
munmap(0x7bfb2053b000, 321504) = 0
close(3) = 0
exit_group(0) = ?
+++ exited with 0 +++
```
[Linux 核心模組運作原理](https://hackmd.io/@sysprog/linux-kernel-module) 中提到在 Linux kernel v6.8.5 中, finit_module 系統呼叫的實作方式已變更,呼叫 idempotent_init_module 後在該函式當中還會呼叫 init_module_from_file ,在 init_module_from_file 才真正呼叫到 load_module。