Linux_kernel编程基础总结
时间:2015/10/9
背景:学习linux内核编程,总结学习中的经验,方便之后查看;
通常我们想弄清楚linux内核是怎么样工作的,如何使用内核接口来编写linux内核代码的第一步都是搭建一个实验环境来做试验的;这里总结一下实验环境的搭建步骤,和我的一些经验;
步骤一、搭建实验环境
这里资源文件总共有两个:hello.c Makefile
Hello.c 是模块的源码;
Makefile 是编译模块的脚本文件;
//hello.c 源码
#include <linux/kernel.h>
#include <linux/module.h>
static int __init mini2440_hello_module_init(void)
{
printk (KERN_WARNING "hello , mini2440\n");
return 0;
}
static int __exit mini2440_bye_module_exit(void)
{
printk (KERN_WARNING "bye , mini2440\n");
return 0;
}
module_init(mini2440_hello_module_init);
module_exit(mini2440_bye_module_exit);
MODULE_LICENSE("GPL");
#Makefile文件
obj-m := hello.o
KERNEL_DIR := /lib/modules/$(shell uname -r)/build
#KERNEL_DIR := /opt/FriendlyARM/mini2440/linux-2.6.32.2
PWD := $(shell pwd)
all:
make -C $(KERNEL_DIR) M=$(PWD) modules
clean:
rm *.o *.ko *.mod.c Module.symvers modules.order
步骤二、编译模块,并执行insmod,rmmod插入卸载模块操作
1、make分析:从hello.c这个模块源码文件上来看,这个模块的主体是一个很简单的结构,声明了模块在加载的时候执行mini2440_hello_module_init; 模块在卸载的时候执行mini2440_bye_module_exit;分别对应着将不同的字符串打印到串口上;细说一下,在hello.c中前两行的头文件肯定的是指内核的头文件$(kernel)/include/linux而不是在/usr/include的用户空间才使用的头文件路径,而我们所要使用的头文件路径是由Makefile文件中定义好我们要明确使用的是那个内核源码来编译的;
从Makefile进行分析;
Obj-m := hello.o
#表示当前编译想要生成一个动态的模块,这个模块依赖于hello.o来生成;而在makefile中,想要生成hello.o默认的将会执行从hello.c生成;因此Makefile将会自动搜索当前路径下是否有hello.c的文件,如果有则生成hello.o,然后有了hello.o则声称hello.ko;这个是makefile自动匹配的语法;
KERNEL_DIR := /lib/modules/$(shell uname-r)/build
#这句话就是我指定我想编译模块所需要的内核源码路径;可以指定你想指定的任意含有内核源码的路径,编译将会生成对应的内核版本的内核模块;因为linux系统中内核模块有着强烈的版本限制,所以只有对应版本的内核源码编出来的内核模块才能够在对应的内核版本系统中运行;
PWD := $(shell pwd)
#这里使用pwd指令获取当前路径,并将他放在PWD这个变量里面,作为下面make –C makefile的入参;
all:
make -C $(KERNEL_DIR) M=$(PWD) modules
#这里all:就是一个目标,也可以说是一个伪目标,没有实际意义,只是用来表示我要开始执行命令了;
#make –C 表示(change)改变当前makefile的路径,切换到其他makefile中去执行,后面跟的就是想要切换到的路径,这里路径被我定义为/lib/modules/$(shell uname -r)/build
这里ll 这个路径发现,他是一个标准的软连接:指向了
/usr/src/linux-headers-2.6.32-74-generic
之后我们跟踪到/usr/src/linux-headers-2.6.32-74-generic;
Ls -l之后发现这里所有资源指向了上一级的linux-headers.6.32-74
其实我们并不需要关心其他资源,Makefile –C切换过来,需要寻找这个路径下的makefile;我们看看这个文件中的makefile是怎么写的;
在ubuntu 10.04_2.6.32-74内核源码makefile中的69行:这里就强调为什么我们在make –C的时候需要传递一个参数M过去,而不是其他参数;当然这里他是以识别M开头的参数,
如果这里我想挑逗他一下,用一个M1来代替,看看会出什么结果:
将会报错:
Makefile说也可以使用SUBDIRS来代替M;你可以试试:
Make 命令行中最后一个modules表示,这里所要编译的是一个module;
当然你要知道当前所运行的都是在内核源码顶层makefile中运行的,在顶层makefile运行到最后,将会从M中拿到扩展的模块源码进行编译;之后将会生成hello.ko文件;
模块名,源码文件名,KO文件名;
之前一直在困惑,通过Insmod./hello.ko这个文件,最终通过lsmod 查看发现有一个模块名字叫做hello,那么这个模块的命名是由谁决定的;这里面涉及到整个KO编译和插入总共有三个文件名;一个是模块的源码.c文件名;hello.c;另一个是Makefile文件中obj-m:=hello.o编译模块名;最后一个是编译生成的hello.ko文件;之后才清晰的明白其中的转则;
1、 不修改资源文件,默认编译并生成了hello.ko文件;修改hello.ko文件名为hello_back.ko然后插入这个KO文件,之后通过lsmod查看,发现模块名依旧是hello,所以说模块名与KO文件名无关;
2、 模块名取决于obj-m后面跟的是什么,这里obj-m跟的是hello.o所以kernel默认将会生成hello模块;因为Obj-m依赖于hello.o,而makefile语法中想要生成hello.o将要在路径下寻找同名的.c文件(hello.c),也就是这里的第一个名字:源码的.c文件名,就是这么用的;