Helloworld 驱动模块加载
介绍
本文引用《linux设备驱动开发》书中部分解释,记录开篇第一章helloworld
程序
以下内容需要掌握如下基础信息linux模块概念、链接编译、c语言基础
内容
helloworld.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hellowolrd_init(void) {
pr_info("Hello world!\n");
return 0;
}
static void __exit hellowolrd_exit(void) {
pr_info("End of the world\n");
}
module_init(hellowolrd_init);
module_exit(hellowolrd_exit);
MODULE_AUTHOR("John Madieu <john.madieu@gmail.com>");
MODULE_LICENSE("GPL");
运行make
命令之后,它会生成两个模块
After running make
command, there will be two modules:
- helloworld.ko
- helloworld-params.ko
第一个模块是基本helloworld驱动程序,第二个也是相同的,但是它接收一些参数,并在内核调试消息中打印这些参数,加载第一个模块后,将在内核中添加两个调试消息,
安装模块
# insmod ./helloworld.ko
卸载模块
# rmmod -f helloworld
内核消息
#dmesg
[...]
[38535.487568] Hello world!
[38542.391099] End of the world
对于第二个模块,可以使用下面方式加载
# insmod ./helloworld-params.ko
如果未提供任何参数,将使用默认值:
$ dmesg
[...]
[37858.595126] Hello world with parameters!
[37858.595129] The *mystr* parameter: hello
[37858.595130] The *myint* parameter: 1
[37858.595131] The *myarr* parameter: 0, 1, 2
[37887.232643] End of the world
我们传入一些参数之后,将打印出如下消息
# insmod ./helloworld-params.ko mystr="packtpub" myint=255 myarr=23,4,7
# dmesg
[...]
[37892.417968] Hello world with parameters!
[37892.417970] The *mystr* parameter: packtpub
[37892.417971] The *myint* parameter: 255
[37892.417972] The *myarr* parameter: 23, 4, 7
[37895.222808] End of the world
模块的入点和出点
内核驱动程序都有入点和出点:前者对应于模块加载时调用的函数(modprobe和insmod,该内容在书中有介绍),后者是模块卸载时执行的函数(在执行rmmod和modprobe -r 时,该内容书中有介绍)。
main()函数使用C/C++编写的每个用户空间程序的入点,当这个函数返回时,程序将退出。而对于内核模块,情况就不一样了:入点可以随意命名,它也不像用户空间程序那样在main()返回是退出,其出点在另一个函数中定义,开发人员 要做的就是通知内核把 哪些函数作为入点或出点来执行。实际上,唯一必须要做的是把它们作为参数提供为module_init()
和module_exit()
宏,将它们标识为相应的加载和删除函数。
综上所述,module_init()
用于声明模块加载(使用insmod或modprobe)时应该调用的函数。初始化函数中要完成的操作是定义模块的行为。module_exit()
用于声明模块卸载(使用rmmod)时应该调用的函数。
代码中__init
和__exit
属性
__init和__exit实际上是在include/linux/init.h中定义的内核宏,如下所示:
#define __init__section(.init.text)
#define __exir__section(.exit.text)
ELF目标文件
编译文件工作方式,ELF目标文件有不同的命名部分组成,其中一部分是必需的,它们称为ELF标准的基础,但也可以根据自己的需要构建任一部分,并由特殊程序使用,内核就是这样做的。如上所属的内核宏的工作方式,如需要了解它的原理ELF目标文件的可执行和可链接格式说明需要了解
可以通过下列命令打印出指定内核模块module.ko的不同组成部分
~/.../LinuxDeviceDriversDevelopment_Code/Chapter02 >>> objdump -h helloworld.ko
helloworld.ko: 文件格式 elf64-x86-64
节:
Idx Name Size VMA LMA File off Algn
0 .text 00000000 0000000000000000 0000000000000000 00000040 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .init.text 00000015 0000000000000000 0000000000000000 00000040 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
2 .exit.text 0000000c 0000000000000000 0000000000000000 00000055 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
3 .rodata.str1.1 00000024 0000000000000000 0000000000000000 00000061 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 __mcount_loc 00000008 0000000000000000 0000000000000000 00000085 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
5 .rodata 0000008c 0000000000000000 0000000000000000 000000a0 2**5
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
6 .rodata.str1.8 00000058 0000000000000000 0000000000000000 00000130 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .modinfo 000000af 0000000000000000 0000000000000000 00000188 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .orc_unwind 0000001e 0000000000000000 0000000000000000 00000237 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .orc_unwind_ip 00000014 0000000000000000 0000000000000000 00000255 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
10 .note.gnu.property 00000030 0000000000000000 0000000000000000 00000270 2**3
CONTENTS, ALLOC, LOAD, READONLY, DATA
11 .note.gnu.build-id 00000024 0000000000000000 0000000000000000 000002a0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
12 .note.Linux 00000030 0000000000000000 0000000000000000 000002c4 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
13 .data 00000000 0000000000000000 0000000000000000 000002f4 2**0
CONTENTS, ALLOC, LOAD, DATA
14 .printk_index 00000010 0000000000000000 0000000000000000 000002f8 2**3
CONTENTS, ALLOC, LOAD, RELOC, DATA
15 .gnu.linkonce.this_module 000003c0 0000000000000000 0000000000000000 00000340 2**6
CONTENTS, ALLOC, LOAD, RELOC, DATA, LINK_ONCE_DISCARD
16 .bss 00000000 0000000000000000 0000000000000000 00000700 2**0
ALLOC
17 .debug_info 000038ec 0000000000000000 0000000000000000 00000700 2**0
CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
18 .debug_abbrev 00000609 0000000000000000 0000000000000000 00003fec 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
19 .debug_aranges 00000060 0000000000000000 0000000000000000 000045f5 2**0
CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
20 .debug_ranges 00000030 0000000000000000 0000000000000000 00004655 2**0
CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
21 .debug_line 000005a7 0000000000000000 0000000000000000 00004685 2**0
CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
22 .debug_str 00003206 0000000000000000 0000000000000000 00004c2c 2**0
CONTENTS, READONLY, DEBUGGING, OCTETS
23 .comment 00000026 0000000000000000 0000000000000000 00007e32 2**0
CONTENTS, READONLY
24 .note.GNU-stack 00000000 0000000000000000 0000000000000000 00007e58 2**0
CONTENTS, READONLY
25 .debug_frame 00000048 0000000000000000 0000000000000000 00007e58 2**3
CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS
26 .BTF 00000050 0000000000000000 0000000000000000 00007ea0 2**0
CONTENTS, READONLY
如上只有少部分属于ELF标准
- .text: 包含程序代码,也称为代码。
- .data: 包含初始化数据,也称为数据段。
- .rodata: 用于只读数据。
- .comment: 注释。
- 未初始化化的数据段,也称为有符号开始的块(block started by symbol,bss)。
ELF链接器
对于代码程序中内核添加的其他部分,讨论为时过早,我们首先要讨论链接器是如何将目标程序文件排列,并将相关.init.text
链接到程序中hellowolrd_init
及.exit.text
链接到程序中hellowolrd_exit
要解释这一行为,首先我们要了解一个叫做链接器(Linux系统上的ld)程序,该程序负责将符号(数据、代码等)放置到生成的二进制文件中的适当部分,以便在程序执行时可以被加载器处理。二进制文件中的这些部分可以自定义、更改它们的默认位置,甚至可以通过提供链接器脚本[称为链接器定义文件(LDF
)或链接器定义脚本(LDS
)]来添加其他部分。要实现这些操作只需通过编译器指令把符号的位置告知链接器即可,GUN C
编译器为此提供了一些属性。Linux内核提供了一个自定义LDS
文件,它位于arch/<arch>/kernel/vmlinux.lds,.s
中。对于要放置在内核LDS文件所映射的专用部分中的符号,使用__init
和__exit
进行标记。
总之,__init
和__exit
是Linux指令(实际上是宏),他们使用C编译器属性指定符号的位置。这些指令指示编译器将以它们为前缀的代码分别放在.init.text
和.exit.text
部分,虽然内核可以访问不同的对象部分。
Helloworld 驱动模块加载的更多相关文章
- linux下自动加载设备驱动程序模块
假设你的设备驱动程序为:yourdrivername.ko 1 cp yourdrivername.ko /lib/modules/"version"/kernel/driver ...
- linux设备和驱动加载的先后顺序
点击打开链接 Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢. Linux系统使用两种方式去加载系统中的模块:动态和静态. 静态加载:将所有 ...
- java HelloWorld 提示“错误: 找不到或无法加载主类 HelloWorld“解决方案
在检查环境变量等前提工作准确无误后,注意要配好CLASSPATH,仍然报“错误: 找不到或无法加载主类 HelloWorld“. 本人工程目录:mygs-maven/src/main/java/hel ...
- 加载驱动模块时Device or resource busy的解决方法
加载驱动模块时Device or resource busy的解决方法 加载驱动模块时Device or resource busy的解决方法 insmod或modprobe驱动模块时Device o ...
- java HelloWorld时报错:"找不到或无法加载主类"问题的解决办法
学习java的第一天: 当我在做Java入门的时候,根据教程写的第一个Java程序是: public class Hello{ public static void main(String args[ ...
- 运行HelloWorld.class是报错(错误: 找不到或无法加载主类 HelloWorld.class)
1.从毕业到现在工作了几个月了,每天都是在写一些js代码,感觉作为一个web程序员,java还是十分重要的,于是自己买了一本java书来边学边练习,然后发现自己连使用记事本来编写的HelloWorld ...
- [ARM-Linux开发]Linux下加载.ko驱动模块的两种方法:insmod与modprobe
假设要加载的驱动程序模块名为SHT21.ko 加载驱动模块 方法一: 进入SHT21.ko驱动模块文件所在的目录,然后直接 insmod SHT21.ko 即可 方法二: 将SHT21.ko文 ...
- 【全网最优方法】JAVA初学:错误: 找不到或无法加载主类HelloWorld
JAVA初学:错误: 找不到或无法加载主类 HelloWorld 我这是看的黑马2019网课(B站)出现的问题. 放一下别人的图,我也是大概的问题:就是javac没问题,java却无论怎么弄都报错. ...
- eclipse springboot运行helloworld错误: 找不到或无法加载主类 xxx.xxx.xxx
这个错误,在网上搜找了好久,说是什么jar包冲突,什么环境配置,我经过验证均是正确的,javac java java -version 都没问题,环境变量也OK,各种解释均没有能够解决我的问题,最后好 ...
随机推荐
- Numpy中重要的广播概念
Numpy中重要的广播概念 广播:简单理解为用于不同大小数组的二元通用函数(加.减.乘等)的一组规则 广播的规则: 如果两个数组的维度数dim不相同,那么小维度数组的形状将会在左边补1 如果shape ...
- SQL之总结(三)
1.怎么在where指定多个值得问题? select * from tb_article where article_id in(10008,10009) 结果如下: 如果是字符串的话: select ...
- android 布局的android:padding 和android:margin的区别
android:layout_marginLeft指该控件距离边父控件的边距, android:paddingLeft指该控件内部内容,如文本距离该控件的边距. 如: 当按钮分别设置以上两个属性时,得 ...
- Emscripten教程之代码可移植性与限制(一)
Emscripten教程之代码可移植性与限制(一) 翻译:云荒杯倾本文是Emscripten-WebAssembly专栏系列文章之一,更多文章请查看专栏.也可以去作者的博客阅读文章.欢迎加入Wasm和 ...
- 设计模式之:抽象工厂模式AbstractFactoryPattern的实现
相比于工厂模式,抽象工厂模式的每个工厂可以创建产品系列,而不是一个产品: 抽象工厂用到的技术:接口.多态.配置文件.反射: 抽象工厂模式的设计原则: 实现客户端创建产品和使用产品的分离,客户端无须了解 ...
- Spark周总结(一)
本周学习内容: 1.搭建虚拟机Spark环境 2.idea编写Scala脚本并在yarn上运行 总结: 这周是回家第一周,虽然没啥事,但是还是想放松放松,也是万事开头难,跟着教程做,但总有几步跟教程上 ...
- 【uniapp 开发】如何给边框添加阴影效果
css的box-shadow是用来添加边框阴影效果的. 属性值详解: 1.inset 可选值,默认阴影在盒子外 使用inset后,阴影在盒子内,即使指定边框或者透明边框,阴影依然存在. 2. 这是头两 ...
- js,nodejs如何判断文件是什么编码格式
nodejs编码只支持utf8的编码方式,无论是打开某个文件或者写.js脚本都得以utf8的编码方式保存,不然程序无法运行,读出来的文件是乱码. 如果是在前台,读取文件是通过FileReader或者F ...
- uni-app中实现图片左滑的效果
template: 1 <view class="my-reg"> 2 <view class="my-regs"> 3 <ima ...
- PowerBI添加中国地图
可以直接在添加视觉对象中添加 或者用此方法 样子: 添加形状地图地图的"位置""图例" 然后去http://datav.aliyun.com/portal/sc ...