1 首先是 静态的编译
这里先空着。
2 然后是动态的编译
首先是内核的代码
由任意一个 module_init() 开始切入
#define module_init(initfn) \
▎ static inline initcall_t __maybe_unused __inittest(void) \
▎ { return initfn; } \
▎ int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));
▎
/* This is only required if you want to be unloadable. */
#define module_exit(exitfn) \
▎ static inline exitcall_t __maybe_unused __exittest(void) \
▎ { return exitfn; } \
▎ void cleanup_module(void) __copy(exitfn) __attribute__((alias(#exitfn)));
重点就是这两段代码, 由于逻辑上是一样的,所以只看 module_init(),
static inline initcall_t __maybe_unused __inittest(void) { return initfn; }
这段代码 , initcall_t 是一个返回值类型, 用于检查 initfn 函数,类型对不对。 至于 __initteset 不知道是干什么的。总之这是一个 检验 initfn 类型对不对的函数。
int init_module(void) __copy(initfn) __attribute__((alias(#initfn))); 这段函数, 定义了一个别名, 将initfn 叫做 init_module.
感觉 __copy(initfn) 好像还跟自定义的段有关, alias 应该是有定义别名的意思。
至此这个函数就分析完了。
还记得 ,我们在 编译 内核模块的时候, 在Makefile 中 使用到了 内核源码的 Makefile 文件,所以 会使用 内核的Makefile 对 驱动文件进行编译。
网上的资料。
我会 会在系统中 使用 insmod 这个命令对驱动进行加载。
接下来就是分析 insmod 了。
busybox 的insmod 命令最终会调用 bb_init_module()
这个函数最终调用到了 init_module() 函数。
init_module 演变成了 一个 syscall 函数。
这个函数最终 成了一个系统调用。
接下来就是关于系统调用的部分。
现在 关键是对 syscall(__NR_init_module, mod, len, opts) 这个函数的分析。
对于这个函数的分析 , 就不能 在 从上往下分析了。
需要从下往上分析, 然后 与这个函数做对接。
先来看看 __NR_init_module 这个宏定义。
__SYSCALL(__NR_init_module, sys_init_module) 这个的含义是 将 __NR_init_module , 与
sys_init_module 关联起来,具体怎么关联的,不清楚。
感觉是这个意思, 就是说 ,当一个系统调用的 值 位105 的稍后, 就会调用 sys_init_module 这个函数。
接下来关键就是 sys_init_module 这个函数。
这个函数 ,在源码中没有明写, 是通过 宏定义展开的。
这个函数最终就会变成 sys_init_module
开始追踪宏定义。
经过这一坨 宏定义展开,
最终。
SYSCALL_DEFINE3(init_module, void __user *, umod,unsigned long, len, const char __user *, uargs)
就变成了。
asmlinkage long sys_init_module(void __user *umod, unsigned long len,
const char __user *uargs);
具体怎么展开的就不分析了,我也不懂。
到目前为止 ,系统调用这里就分析完了。
接下来我其实可以 自己写一个 系统调用,偷个鸡。
就是利用这个函数,来关联自己定义的函数。
#define __NR_init_module 105
__SYSCALL(__NR_init_module, sys_init_module)
感觉 这不就是 在写驱动吗。 把系统调用当成 驱动来用。
接下里自己实现 一个 函数,用于在板卡上 开灯, 关联一个系统调用。
先空着。