[linux小水滴]内核模块编译入门

一、编译的流程

#独立模块编译的编译流程
mkdir modules #创建一个文件夹modules
vi hello.c #创建一个c文件 hello.c
vi Makefile #创建一个Makefile文件
make #输入编译命令make,此时会看到modules文件夹中生成了一个.ko文件
sudo insmod hello.ko #用insmod命令载入模块
lsmod | grep hello #lsmod命令查看所有模块,这里用grep查找所有模块中有无hello
modinfo hello.ko #查看内核模块文件相关信息,包含大小、依赖关系等内容
dmesg | tail -l #用dmesg查看系统log,这里查找所有log中最末尾的那几条log
sudo rmmod hello.ko #rmmod删除模块
dmesg | tail -l #查看log

1.1 Makefile文件

Makefile 文件描述了 Linux 系统下 C/C++ 工程的编译规则,它用来自动化编译 C/C++ 项目。一旦写编写好 Makefile 文件,只需要一个 make 命令,整个工程就开始自动编译,不再需要手动执行 GCC 命令。
一个中大型 C/C++ 工程的源文件有成百上千个,它们按照功能、模块、类型分别放在不同的目录中,Makefile 文件定义了一系列规则,指明了源文件的编译顺序、依赖关系、是否需要重新编译等。

1.2 .ko文件

是kernel object文件(内核模块),该文件的意义就是把内核的一些功能移动到内核外边,需要的时候插入内核,不需要时卸载。

1.3 insmod & rmmod

insmod命令用于将给定的模块加载到内核中。Linux有许多功能是通过模块的方式,在需要时才载入kernel。如此可使kernel较为精简,进而提高效率,以及保有较大的弹性。这类可载入的模块,通常是设备驱动程序。
rmmod命令用于从当前运行的内核中移除指定的内核模块。执行rmmod指令,可删除不需要的模块。Linux操作系统的核心具有模块化的特性,应此在编译核心时,务须把全部的功能都放如核心。你可以将这些功能编译成一个个单独的模块,待有需要时再分别载入它们。

1.4 两种内核编译方法

(1)独立模块编译
就是本小节最开始所示的流程。单独一个Makefile。在下一小节将会给出。
(2)放入内核源码中编译
这种方法的编译配置和(1)有所不同。
①把自己的内核代码放入到内核合适的位置,一般测试用的模块放在bsp/kernel/kernel4.14/drivers/misc下面
②把自己开发的功能添加到linux内核的配置选项中,使用户能够选中这项功能并编译。
在Kconfig文件结尾,endmenu的前面加入一个config选项

config 2020_HELLO
        bool "This is my first drive "
        default y
        help
           The driver hello.   

③构建或修改Makefile。在misc文件夹中的Makefile里添加

obj-$(CONFIG_2020_HELLO)        += hello.o

也可以在Makefile中直接添加:

obj-y                           += 模块文件夹名/

④执行make
看make后的config的menu。用make menuconfig命令。
下面所示为独立模块编译。

1.5 编译log查看

(1)kernel代码中插入打log的函数pr_info()或者printk()
(2)查看log用dmesg命令或cat /proc/kmsg看全部的log。dmesg | tail -l看最后几条

二、第一个内核模块代码

//hello.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/delay.h>

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("kthread test");
MODULE_VERSION("0.1");

static struct task_struct *my_task = NULL;

static int my_kthread(void *data) {
    char *str = (char *)data;

    pr_info("my kthread data: %s\n", str);
    pr_info("my kthread smp_processor_id %d\n", smp_processor_id());
    while(!kthread_should_stop()) {
        msleep(5000);
        pr_info("my kthread: living. smp_processor_id %d\n", smp_processor_id());
        pr_info("=========================================\n");
    }
    pr_info("my kthread: stop\n");
    return 0;
}

static int __init my_init(void)
{
    pr_info("my init.\n");
    pr_info("smp_processor_id %d\n", smp_processor_id());

    my_task = kthread_run(my_kthread, "hello my kthread", "mykthread-%s", "test");

    pr_info("my init finish.\n");
    pr_info("=========================================\n");
    return 0;
}

static void __exit my_exit(void)
{
    pr_info("my exit.\n");
    pr_info("smp_processor_id %d\n", smp_processor_id());

    if (my_task) {
        pr_info("stop kthread\n");
        kthread_stop(my_task);
    }

    pr_info("my exit finish.\n");
    pr_info("=========================================\n");
}

module_init(my_init);
module_exit(my_exit);
#Makefile
obj-m := hello.o #
KERNELBUILD :=/lib/modules/$(shell uname -r)/build
default:
	make -C $(KERNELBUILD) M=$(shell pwd) modules #注意这一行最前面必须是tab
clean:
	rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers *.tmp_versions​
#实际操作
di@ubuntu:~/modules/hello$ make clean #删除之前的载入模块是生成的多余文件
rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers *.tmp_versions​
di@ubuntu:~/modules/hello$ make
make -C /lib/modules/4.2.0-27-generic/build M=/home/di.shen/modules/hello modules
make[1]: Entering directory `/usr/src/linux-headers-4.2.0-27-generic'
  CC [M]  /home/di.shen/modules/hello/hello.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/di.shen/modules/hello/hello.mod.o
  LD [M]  /home/di.shen/modules/hello/hello.ko
make[1]: Leaving directory `/usr/src/linux-headers-4.2.0-27-generic'
di@ubuntu:~/modules/hello$ sudo insmod hello.ko
di@ubuntu:~/modules/hello$ lsmod | grep hello
hello                  16384  0 
di@ubuntu:~/modules/hello$ dmesg | tail -l
[ 8279.854305] my kthread data: hello my kthread
[ 8279.854306] my kthread smp_processor_id 3
[ 8284.865161] my kthread: living. smp_processor_id 4
[ 8284.865163] =========================================
[ 8289.878954] my kthread: living. smp_processor_id 5
[ 8289.878959] =========================================
[ 8294.892851] my kthread: living. smp_processor_id 0
[ 8294.892856] =========================================
[ 8299.906715] my kthread: living. smp_processor_id 1
[ 8299.906717] =========================================
di@ubuntu:~/modules/hello$ sudo rmmod hello.ko
di@ubuntu:~/modules/hello$ dmesg | tail -l
[ 8365.086795] my kthread: living. smp_processor_id 3
[ 8365.086796] =========================================
[ 8369.316343] my exit.
[ 8369.316345] smp_processor_id 0
[ 8369.316345] stop kthread
[ 8370.100650] my kthread: living. smp_processor_id 4
[ 8370.100652] =========================================
[ 8370.100667] my kthread: stop
[ 8370.100721] my exit finish.
[ 8370.100726] =========================================

三、问题解决

WARNING: “mcount” xxx.ko undefined!
解决方法是:重装(升级)gcc,重装时必须先remove原来版本的gcc。
1.sudo apt-get remove gcc
2.sudo apt-get install gcc

四、参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是微信小程序底部导航中间水滴凹槽的实现方法: 1. 在app.json文件中设置tabBar的样式,将中间按钮的位置留出来,例如: ```json "tabBar": { "color": "#999999", "selectedColor": "#1296db", "backgroundColor": "#ffffff", "borderStyle": "black", "list": [ { "pagePath": "pages/index/index", "text": "首页", "iconPath": "images/tabbar/home.png", "selectedIconPath": "images/tabbar/home_active.png" }, { "pagePath": "pages/mine/mine", "text": "我的", "iconPath": "images/tabbar/mine.png", "selectedIconPath": "images/tabbar/mine_active.png" }, { "pagePath": "pages/center/center", "text": "", "iconPath": "images/tabbar/center.png", "selectedIconPath": "images/tabbar/center_active.png" }, { "pagePath": "pages/cart/cart", "text": "购物车", "iconPath": "images/tabbar/cart.png", "selectedIconPath": "images/tabbar/cart_active.png" }, { "pagePath": "pages/category/category", "text": "分类", "iconPath": "images/tabbar/category.png", "selectedIconPath": "images/tabbar/category_active.png" } ] } ``` 2. 在TabBar组件中添加中间按钮的样式,例如: ```css .tabbar-center { position: fixed; left: 50%; bottom: 0; transform: translateX(-50%); z-index: 999; width: 60rpx; height: 60rpx; border-radius: 50%; background-color: #1296db; box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.15); } ``` 3. 在TabBar组件中添加中间按钮的点击事件,例如: ```javascript methods: { onCenterClick() { wx.navigateTo({ url: '/pages/center/center' }) } } ``` 4. 在TabBar组件中添加中间按钮的图片和文字,例如: ```html <view class="tabbar-center" @tap="onCenterClick"> <image src="/static/images/tabbar/center.png" class="tabbar-center-icon"></image> <text class="tabbar-center-text">中心</text> </view> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值